Decompiled source of SorosQualityOfLife v1.0.21

SorosQualityOfLife.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("SorosQualityOfLife")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.21.0")]
[assembly: AssemblyInformationalVersion("1.0.21")]
[assembly: AssemblyProduct("SorosQualityOfLife")]
[assembly: AssemblyTitle("SorosQualityOfLife")]
[assembly: AssemblyVersion("1.0.21.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 SorosQualityOfLife
{
	internal static class Acc
	{
		public delegate void GetSlotD(CookingStation c, int slot, out string item, out float time, out Status status, out bool cheated);

		public delegate void SetSlotD(CookingStation c, int slot, string item, float time, Status status, bool cheated);

		public static FieldRef<BaseAI, ZSyncAnimation> BaseAI_animator;

		public static FieldRef<Beehive, ZNetView> Beehive_nview;

		public static FieldRef<Container, ZNetView> Container_nview;

		public static FieldRef<CookingStation, ZNetView> Cooking_nview;

		public static FieldRef<Fermenter, ZNetView> Fermenter_nview;

		public static FieldRef<Fireplace, ZNetView> Fireplace_nview;

		public static FieldRef<SapCollector, ZNetView> Sap_nview;

		public static FieldRef<Smelter, ZNetView> Smelter_nview;

		public static FieldRef<Tameable, ZNetView> Tameable_nview;

		public static FieldRef<Tameable, MonsterAI> Tameable_monsterAI;

		public static FieldRef<InventoryGui, InventoryGrid> Gui_containerGrid;

		public static FieldRef<InventoryGui, Recipe> Gui_craftRecipe;

		public static FieldRef<InventoryGui, ItemData> Gui_craftUpgradeItem;

		public static FieldRef<InventoryGui, Container> Gui_currentContainer;

		public static FieldRef<InventoryGui, int> Gui_dragAmount;

		public static FieldRef<InventoryGui, Inventory> Gui_dragInventory;

		public static FieldRef<InventoryGui, ItemData> Gui_dragItem;

		public static FieldRef<InventoryGui, bool> Gui_multiCrafting;

		public static FieldRef<Player, List<Food>> Player_foods;

		public static FieldRef<ZNetScene, Dictionary<int, GameObject>> Scene_namedPrefabs;

		private static FieldInfo _reqUpgrader;

		public static Func<Beehive, int> Beehive_GetHoneyLevel;

		public static Func<SapCollector, int> Sap_GetLevel;

		public static Func<Container, long, bool> Container_CheckAccess;

		public static Action<Container> Container_CheckForChanges;

		public static Func<CookingStation, float> Cooking_GetFuel;

		public static Func<CookingStation, bool> Cooking_IsFireLit;

		public static Func<CookingStation, ItemData, bool> Cooking_IsItemAllowed;

		public static Func<CookingStation, string, bool> Cooking_IsItemDone;

		public static GetSlotD Cooking_GetSlot;

		public static SetSlotD Cooking_SetSlot;

		public static Func<Fermenter, string> Fermenter_GetContentName;

		public static Func<Fermenter, int, ItemConversion> Fermenter_GetConversion;

		public static Func<Fermenter, Status> Fermenter_GetStatus;

		public static Func<Fermenter, ItemData, bool> Fermenter_IsItemAllowed;

		public static Action<InventoryGui, ItemData, Inventory, int> Gui_SetupDragItem;

		public static Action<InventoryGui, bool> Gui_UpdateCraftingPanel;

		public static Func<Smelter, float> Smelter_GetFuel;

		public static Func<Smelter, string, ItemConversion> Smelter_GetConversion;

		public static Func<Smelter, int> Smelter_GetQueueSize;

		public static Func<Smelter, ItemData, bool> Smelter_IsItemAllowed;

		public static Action<Smelter> Smelter_SpawnProcessed;

		public static Action<Tameable, ItemDrop> Tameable_OnConsumedItem;

		public static readonly List<string> Failed = new List<string>();

		private static FieldInfo _stUpgrader;

		private static bool _stUpgraderInit;

		private static MethodInfo _effCreate;

		private static MethodInfo _msg;

		private static FieldRef<T, F> F<T, F>(string name)
		{
			try
			{
				return AccessTools.FieldRefAccess<T, F>(name);
			}
			catch (Exception ex)
			{
				Failed.Add(typeof(T).Name + "." + name + " (" + ex.Message + ")");
				return null;
			}
		}

		private static D M<D>(Type t, string name, Type[] args = null) where D : Delegate
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(t, name, args, (Type[])null);
				if (methodInfo == null)
				{
					Failed.Add(t.Name + "." + name + "()");
					return null;
				}
				return AccessTools.MethodDelegate<D>(methodInfo, (object)null, true);
			}
			catch (Exception ex)
			{
				Failed.Add(t.Name + "." + name + "() (" + ex.Message + ")");
				return null;
			}
		}

		public static void Init()
		{
			BaseAI_animator = F<BaseAI, ZSyncAnimation>("m_animator");
			Beehive_nview = F<Beehive, ZNetView>("m_nview");
			Container_nview = F<Container, ZNetView>("m_nview");
			Cooking_nview = F<CookingStation, ZNetView>("m_nview");
			Fermenter_nview = F<Fermenter, ZNetView>("m_nview");
			Fireplace_nview = F<Fireplace, ZNetView>("m_nview");
			Sap_nview = F<SapCollector, ZNetView>("m_nview");
			Smelter_nview = F<Smelter, ZNetView>("m_nview");
			Tameable_nview = F<Tameable, ZNetView>("m_nview");
			Tameable_monsterAI = F<Tameable, MonsterAI>("m_monsterAI");
			Gui_containerGrid = F<InventoryGui, InventoryGrid>("m_containerGrid");
			Gui_craftRecipe = F<InventoryGui, Recipe>("m_craftRecipe");
			Gui_craftUpgradeItem = F<InventoryGui, ItemData>("m_craftUpgradeItem");
			Gui_currentContainer = F<InventoryGui, Container>("m_currentContainer");
			Gui_dragAmount = F<InventoryGui, int>("m_dragAmount");
			Gui_dragInventory = F<InventoryGui, Inventory>("m_dragInventory");
			Gui_dragItem = F<InventoryGui, ItemData>("m_dragItem");
			Gui_multiCrafting = F<InventoryGui, bool>("m_multiCrafting");
			Player_foods = F<Player, List<Food>>("m_foods");
			Scene_namedPrefabs = F<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs");
			_reqUpgrader = AccessTools.Field(typeof(Requirement), "m_upgraderResource");
			Beehive_GetHoneyLevel = M<Func<Beehive, int>>(typeof(Beehive), "GetHoneyLevel");
			Sap_GetLevel = M<Func<SapCollector, int>>(typeof(SapCollector), "GetLevel");
			Container_CheckAccess = M<Func<Container, long, bool>>(typeof(Container), "CheckAccess", new Type[1] { typeof(long) });
			Container_CheckForChanges = M<Action<Container>>(typeof(Container), "CheckForChanges");
			Cooking_GetFuel = M<Func<CookingStation, float>>(typeof(CookingStation), "GetFuel");
			Cooking_IsFireLit = M<Func<CookingStation, bool>>(typeof(CookingStation), "IsFireLit");
			Cooking_IsItemAllowed = M<Func<CookingStation, ItemData, bool>>(typeof(CookingStation), "IsItemAllowed", new Type[1] { typeof(ItemData) });
			Cooking_IsItemDone = M<Func<CookingStation, string, bool>>(typeof(CookingStation), "IsItemDone", new Type[1] { typeof(string) });
			Cooking_GetSlot = M<GetSlotD>(typeof(CookingStation), "GetSlot");
			Cooking_SetSlot = M<SetSlotD>(typeof(CookingStation), "SetSlot");
			Fermenter_GetContentName = M<Func<Fermenter, string>>(typeof(Fermenter), "GetContentName");
			Fermenter_GetConversion = M<Func<Fermenter, int, ItemConversion>>(typeof(Fermenter), "GetItemConversion", new Type[1] { typeof(int) });
			Fermenter_GetStatus = M<Func<Fermenter, Status>>(typeof(Fermenter), "GetStatus");
			Fermenter_IsItemAllowed = M<Func<Fermenter, ItemData, bool>>(typeof(Fermenter), "IsItemAllowed", new Type[1] { typeof(ItemData) });
			Gui_SetupDragItem = M<Action<InventoryGui, ItemData, Inventory, int>>(typeof(InventoryGui), "SetupDragItem");
			Gui_UpdateCraftingPanel = M<Action<InventoryGui, bool>>(typeof(InventoryGui), "UpdateCraftingPanel");
			Smelter_GetFuel = M<Func<Smelter, float>>(typeof(Smelter), "GetFuel");
			Smelter_GetConversion = M<Func<Smelter, string, ItemConversion>>(typeof(Smelter), "GetItemConversion", new Type[1] { typeof(string) });
			Smelter_GetQueueSize = M<Func<Smelter, int>>(typeof(Smelter), "GetQueueSize");
			Smelter_IsItemAllowed = M<Func<Smelter, ItemData, bool>>(typeof(Smelter), "IsItemAllowed", new Type[1] { typeof(ItemData) });
			Smelter_SpawnProcessed = M<Action<Smelter>>(typeof(Smelter), "SpawnProcessed");
			Tameable_OnConsumedItem = M<Action<Tameable, ItemDrop>>(typeof(Tameable), "OnConsumedItem", new Type[1] { typeof(ItemDrop) });
		}

		public static ZNetView NView(Container c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Container_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(Smelter c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Smelter_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(CookingStation c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Cooking_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(Fermenter c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Fermenter_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(Fireplace c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Fireplace_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(Beehive c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Beehive_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(SapCollector c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Sap_nview.Invoke(c);
			}
			return null;
		}

		public static ZNetView NView(Tameable c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return Tameable_nview.Invoke(c);
			}
			return null;
		}

		public static Container CurrentContainer(InventoryGui g)
		{
			if (!((Object)(object)g == (Object)null) && Gui_currentContainer != null)
			{
				return Gui_currentContainer.Invoke(g);
			}
			return null;
		}

		public static bool StationIsUpgrader(CraftingStation st)
		{
			if (!_stUpgraderInit)
			{
				_stUpgraderInit = true;
				_stUpgrader = AccessTools.Field(typeof(CraftingStation), "m_upgrader");
			}
			try
			{
				return (Object)(object)st != (Object)null && _stUpgrader != null && (bool)_stUpgrader.GetValue(st);
			}
			catch
			{
				return false;
			}
		}

		public static bool IsUpgraderResource(Requirement r)
		{
			if (_reqUpgrader != null)
			{
				return (bool)_reqUpgrader.GetValue(r);
			}
			return false;
		}

		public static bool Probe(out string why)
		{
			why = null;
			try
			{
				Init();
			}
			catch (Exception ex)
			{
				why = ex.ToString();
				return false;
			}
			if (Gui_currentContainer == null || Container_nview == null || Player_foods == null)
			{
				why = "missing core members: " + string.Join(", ", Failed);
				return false;
			}
			return true;
		}

		internal static void Effects(EffectList e, Vector3 pos, Quaternion rot)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (e == null)
				{
					return;
				}
				if (_effCreate == null)
				{
					_effCreate = AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null);
				}
				if (!(_effCreate == null))
				{
					ParameterInfo[] parameters = _effCreate.GetParameters();
					object[] array = new object[parameters.Length];
					for (int i = 0; i < parameters.Length; i++)
					{
						array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : (parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null));
					}
					array[0] = pos;
					if (parameters.Length > 1)
					{
						array[1] = rot;
					}
					_effCreate.Invoke(e, array);
				}
			}
			catch
			{
			}
		}

		internal static void Msg(string text)
		{
			try
			{
				if ((Object)(object)MessageHud.instance == (Object)null)
				{
					return;
				}
				if (_msg == null)
				{
					_msg = AccessTools.Method(typeof(MessageHud), "ShowMessage", (Type[])null, (Type[])null);
				}
				if (!(_msg == null))
				{
					ParameterInfo[] parameters = _msg.GetParameters();
					object[] array = new object[parameters.Length];
					for (int i = 0; i < parameters.Length; i++)
					{
						array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : (parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null));
					}
					array[0] = (object)(MessageType)2;
					array[1] = text;
					_msg.Invoke(MessageHud.instance, array);
				}
			}
			catch
			{
			}
		}
	}
	internal static class AnimalFeeder
	{
		[HarmonyPatch(typeof(Tameable), "Awake")]
		private static class TameableAwake
		{
			private static void Postfix(Tameable __instance)
			{
				Safe.Run("Reg.Tameable", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<string>("SoroQoL_Feed", (Action<long, string>)delegate(long sender, string prefab)
						{
							Safe.Run("Feed", delegate
							{
								if (nv.IsOwner())
								{
									GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
									ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
									MonsterAI val2 = Acc.Tameable_monsterAI.Invoke(__instance);
									if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
									{
										if (val2.m_onConsumedItem != null)
										{
											val2.m_onConsumedItem(val);
										}
										else
										{
											Acc.Tameable_OnConsumedItem(__instance, val);
										}
										ZSyncAnimation obj = Acc.BaseAI_animator.Invoke((BaseAI)(object)val2);
										if (obj != null)
										{
											obj.SetTrigger("consume");
										}
									}
								}
							});
						});
					}
				});
			}
		}

		internal const string RpcFeed = "SoroQoL_Feed";

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

		public static void Tick(SpecialChest chest, Inventory inv)
		{
			//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_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)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)chest).transform.position;
			float range = chest.Range;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || allCharacter.IsPlayer() || allCharacter.IsDead() || Vector3.Distance(((Component)allCharacter).transform.position, position) > range)
				{
					continue;
				}
				Tameable component = ((Component)allCharacter).GetComponent<Tameable>();
				MonsterAI component2 = ((Component)allCharacter).GetComponent<MonsterAI>();
				if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || component2.m_consumeItems == null || component2.m_consumeItems.Count == 0)
				{
					continue;
				}
				ZNetView val = Acc.NView(component);
				if ((Object)(object)val == (Object)null || !val.IsValid())
				{
					continue;
				}
				bool flag = allCharacter.IsTamed();
				if ((flag && !Cfg.FeedTamed) || (!flag && (!Cfg.FeedWild || component.m_tamingTime <= 0f)) || !component.IsHungry())
				{
					continue;
				}
				ZDOID uid = val.GetZDO().m_uid;
				if (_cooldown.TryGetValue(uid, out var value) && Time.time < value)
				{
					continue;
				}
				ItemData val2 = null;
				ItemDrop val3 = null;
				foreach (ItemData it in inv.GetAllItems())
				{
					val3 = ((IEnumerable<ItemDrop>)component2.m_consumeItems).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop c) => Object.op_Implicit((Object)(object)c) && c.m_itemData.m_shared.m_name == it.m_shared.m_name));
					if (Object.op_Implicit((Object)(object)val3))
					{
						val2 = it;
						break;
					}
				}
				if (val2 != null && val.IsOwner() && inv.RemoveItem(val2, 1))
				{
					_cooldown[uid] = Time.time + Cfg.AnimalCooldown;
					val.InvokeRPC("SoroQoL_Feed", new object[1] { ((Object)((Component)val3).gameObject).name });
				}
			}
		}
	}
	public enum ChestMode
	{
		All,
		Smelter,
		BlastFurnace,
		Kiln,
		EitrRefinery,
		Fermenter,
		Beehive,
		SapCollector,
		CookingStation,
		Oven,
		Fuel,
		WindmillSpinningWheel,
		AnimalFeeding,
		Windmill,
		SpinningWheel
	}
	public enum StationKind
	{
		Other,
		Smelter,
		BlastFurnace,
		Kiln,
		EitrRefinery,
		Fermenter,
		Beehive,
		SapCollector,
		CookingStation,
		Oven,
		Fire,
		Windmill,
		HotTub,
		SpinningWheel
	}
	internal static class Kinds
	{
		public static readonly ChestMode[] PickerOrder = new ChestMode[15]
		{
			ChestMode.All,
			ChestMode.Smelter,
			ChestMode.BlastFurnace,
			ChestMode.Kiln,
			ChestMode.EitrRefinery,
			ChestMode.Fermenter,
			ChestMode.Beehive,
			ChestMode.SapCollector,
			ChestMode.CookingStation,
			ChestMode.Oven,
			ChestMode.Windmill,
			ChestMode.SpinningWheel,
			ChestMode.WindmillSpinningWheel,
			ChestMode.Fuel,
			ChestMode.AnimalFeeding
		};

		public static readonly string[] ModeLabels = new string[15]
		{
			"All", "Smelter", "Blast Furnace", "Kiln", "Eitr Refinery", "Fermenter", "Beehive", "Sap Collector", "Cooking Station", "Oven",
			"Fuel", "Windmill + Spinning Wheel (old)", "Animal Feeding", "Windmill", "Spinning Wheel"
		};

		public static string Label(ChestMode m)
		{
			if (m < ChestMode.All || (int)m >= ModeLabels.Length)
			{
				return "All";
			}
			return ModeLabels[(int)m];
		}

		public static StationKind Of(Smelter s)
		{
			return s.m_name switch
			{
				"$piece_smelter" => StationKind.Smelter, 
				"$piece_blastfurnace" => StationKind.BlastFurnace, 
				"$piece_charcoalkiln" => StationKind.Kiln, 
				"$piece_eitrrefinery" => StationKind.EitrRefinery, 
				"$piece_windmill" => StationKind.Windmill, 
				"$piece_spinningwheel" => StationKind.SpinningWheel, 
				"$piece_bathtub" => StationKind.HotTub, 
				_ => StationKind.Other, 
			};
		}

		public static StationKind Of(CookingStation c)
		{
			if (!(c.m_name == "$piece_oven"))
			{
				return StationKind.CookingStation;
			}
			return StationKind.Oven;
		}

		public static bool Matches(ChestMode m, StationKind k)
		{
			switch (m)
			{
			case ChestMode.All:
				return true;
			case ChestMode.Smelter:
				return k == StationKind.Smelter;
			case ChestMode.BlastFurnace:
				return k == StationKind.BlastFurnace;
			case ChestMode.Kiln:
				return k == StationKind.Kiln;
			case ChestMode.EitrRefinery:
				return k == StationKind.EitrRefinery;
			case ChestMode.Fermenter:
				return k == StationKind.Fermenter;
			case ChestMode.Beehive:
				return k == StationKind.Beehive;
			case ChestMode.SapCollector:
				return k == StationKind.SapCollector;
			case ChestMode.CookingStation:
				return k == StationKind.CookingStation;
			case ChestMode.Oven:
				return k == StationKind.Oven;
			case ChestMode.Fuel:
				return true;
			case ChestMode.WindmillSpinningWheel:
				if (k != StationKind.Windmill)
				{
					return k == StationKind.SpinningWheel;
				}
				return true;
			case ChestMode.Windmill:
				return k == StationKind.Windmill;
			case ChestMode.SpinningWheel:
				return k == StationKind.SpinningWheel;
			default:
				return false;
			}
		}
	}
	internal static class ChestPickerGui
	{
		private static Rect _rect = new Rect(20f, 120f, 260f, 0f);

		private static SpecialChest _dragChest;

		private static SpecialChest _nameChest;

		private static string _nameBuf = "";

		internal static bool Typing;

		private const string NameCtl = "SoroQoL_Name";

		private const string TargetCtl = "SoroQoL_Target";

		private static string _targetBuf = "";

		private static float _dragValue;

		private static void TextRow(string label, string ctl, ref string buf, string current, Action<string> save, ref bool typing)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			GUILayout.Label(label, Array.Empty<GUILayoutOption>());
			Event current2 = Event.current;
			bool num = GUI.GetNameOfFocusedControl() == ctl;
			bool flag = num && (int)current2.type == 4 && ((int)current2.keyCode == 13 || (int)current2.keyCode == 271);
			bool flag2 = num && (int)current2.type == 4 && (int)current2.keyCode == 27;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.SetNextControlName(ctl);
			buf = GUILayout.TextField(buf ?? "", 30, Array.Empty<GUILayoutOption>());
			bool num2 = GUILayout.Button("Save", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.EndHorizontal();
			if (num2 || flag)
			{
				save(buf);
				buf = SpecialChest.Sanitize(buf);
				GUI.FocusControl((string)null);
				if (flag)
				{
					current2.Use();
				}
			}
			else if (flag2)
			{
				GUI.FocusControl((string)null);
				buf = current;
				current2.Use();
			}
			if (GUI.GetNameOfFocusedControl() == ctl)
			{
				typing = true;
			}
		}

		private static void List(ChestMode cur, bool push, Action<ChestMode> set)
		{
			ChestMode[] pickerOrder = Kinds.PickerOrder;
			foreach (ChestMode chestMode in pickerOrder)
			{
				if ((push || !SpecialChest.InputOnly(chestMode)) && (chestMode != ChestMode.WindmillSpinningWheel || cur == chestMode) && GUILayout.Toggle(cur == chestMode, Kinds.Label(chestMode), Array.Empty<GUILayoutOption>()) && cur != chestMode)
				{
					set(chestMode);
				}
			}
		}

		public static void Draw()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_0093: 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)
			if (!Cfg.StationChests)
			{
				Typing = false;
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			Container val = Acc.CurrentContainer(instance);
			if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible() || (Object)(object)val == (Object)null)
			{
				Typing = false;
				_nameChest = null;
				return;
			}
			SpecialChest sc = ((Component)val).GetComponent<SpecialChest>();
			if ((Object)(object)sc == (Object)null || !SettingsButton.Open)
			{
				Typing = false;
				_nameChest = null;
				return;
			}
			_rect = GUILayout.Window(20640, _rect, (WindowFunction)delegate
			{
				if ((Object)(object)_nameChest != (Object)(object)sc)
				{
					_nameChest = sc;
					_nameBuf = sc.CustomName;
					_targetBuf = sc.TargetName;
				}
				bool typing = false;
				TextRow("Name (empty = default):", "SoroQoL_Name", ref _nameBuf, sc.CustomName, sc.RequestName, ref typing);
				if (sc.IsTransfer)
				{
					TextRow("Target chest name:", "SoroQoL_Target", ref _targetBuf, sc.TargetName, sc.RequestTarget, ref typing);
				}
				Typing = typing;
				int role = sc.Role;
				bool isFeeder = sc.IsFeeder;
				if (isFeeder && sc.Paused)
				{
					GUILayout.Label("Feeding is PAUSED (converted old chest). Items stay in the chest.", Array.Empty<GUILayoutOption>());
					if (GUILayout.Button("Resume feeding", Array.Empty<GUILayoutOption>()))
					{
						sc.RequestPaused(paused: false);
					}
				}
				if (!sc.IsTransfer)
				{
					GUILayout.Label("Role:", Array.Empty<GUILayoutOption>());
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					for (int i = 0; i <= 1; i++)
					{
						if (GUILayout.Toggle(role == i, SpecialChest.RoleLabel(i), Array.Empty<GUILayoutOption>()) && role != i)
						{
							sc.RequestRole(i);
						}
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.Label(isFeeder ? "Push into:" : "Collect from:", Array.Empty<GUILayoutOption>());
				List(sc.Mode, isFeeder, sc.RequestMode);
				float num = (((Object)(object)_dragChest == (Object)(object)sc && _dragValue > 0f) ? _dragValue : sc.Range);
				GUILayout.Label($"Range: {num:0} m", Array.Empty<GUILayoutOption>());
				float num2 = Mathf.Round(GUILayout.HorizontalSlider(num, 5f, Mathf.Floor(sc.MaxRange), Array.Empty<GUILayoutOption>()));
				if (Mathf.Abs(num2 - num) >= 1f)
				{
					_dragChest = sc;
					_dragValue = num2;
					sc.RequestRange(num2);
				}
				else if ((Object)(object)_dragChest == (Object)(object)sc && Mathf.Abs(sc.Range - _dragValue) < 0.5f)
				{
					_dragValue = 0f;
				}
				GUI.DragWindow();
			}, "Soro's QoL", Array.Empty<GUILayoutOption>());
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class SpecialChestHover
	{
		private static void Postfix(Container __instance, ref string __result)
		{
			try
			{
				PostfixImpl(__instance, ref __result);
			}
			catch (Exception e)
			{
				Safe.Report("ChestPickerGui.cs:Postfix", e);
			}
		}

		private static void PostfixImpl(Container __instance, ref string __result)
		{
			try
			{
				SpecialChest component = ((Component)__instance).GetComponent<SpecialChest>();
				if (!((Object)(object)component == (Object)null))
				{
					string customName = component.CustomName;
					if (customName.Length > 0)
					{
						string text = __instance.m_name ?? "";
						int num = ((text.Length > 0) ? __result.IndexOf(text, StringComparison.Ordinal) : (-1));
						__result = ((num >= 0) ? (__result.Substring(0, num) + "\"" + customName + "\" (" + text + ")" + __result.Substring(num + text.Length)) : ("\"" + customName + "\"\n" + __result));
					}
					if (component.IsTransfer)
					{
						__result = __result + "\nMode: " + Kinds.Label(component.Mode);
						string targetName = component.TargetName;
						__result += ((targetName.Length == 0) ? "\n→ (no target set)" : ("\n→ \"" + targetName + "\" (" + component.TransferStatus() + ")"));
					}
					else
					{
						__result = __result + "\nRole: " + SpecialChest.RoleLabel(component.Role) + ((component.IsFeeder && component.Paused) ? " (paused)" : "") + "\nMode: " + Kinds.Label(component.Mode);
					}
				}
			}
			catch (Exception e)
			{
				Safe.Report("Hover", e);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Update")]
	internal static class SettingsButton
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__5_0;

			internal void <Create>b__5_0()
			{
				Open = !Open;
			}
		}

		internal static bool Open;

		private static Button _btn;

		private static Container _last;

		private static void Postfix(InventoryGui __instance)
		{
			try
			{
				PostfixImpl(__instance);
			}
			catch (Exception e)
			{
				Safe.Report("SettingsButton", e);
			}
		}

		private static void PostfixImpl(InventoryGui gui)
		{
			Container val = (InventoryGui.IsVisible() ? Acc.CurrentContainer(gui) : null);
			if ((Object)(object)val != (Object)(object)_last)
			{
				Open = false;
				_last = val;
			}
			bool flag = Plugin.Enabled && Cfg.StationChests && (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<SpecialChest>() != (Object)null;
			if (flag && (Object)(object)_btn == (Object)null)
			{
				Create(gui);
			}
			if ((Object)(object)_btn != (Object)null && ((Component)_btn).gameObject.activeSelf != flag)
			{
				((Component)_btn).gameObject.SetActive(flag);
			}
		}

		private static void Create(InventoryGui gui)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			Button stackAllButton = gui.m_stackAllButton;
			if ((Object)(object)stackAllButton == (Object)null)
			{
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)stackAllButton).gameObject, ((Component)stackAllButton).transform.parent);
			((Object)val).name = "SoroQoL_Settings";
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren)
			{
				string name = ((object)val2).GetType().Name;
				if (name == "UIGamePad" || name == "Localize")
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			foreach (Transform item in val.transform)
			{
				Transform val3 = item;
				if (((Object)val3).name.ToLowerInvariant().Contains("gamepad") || ((Object)val3).name.ToLowerInvariant().Contains("hint"))
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
			RectTransform val4 = (RectTransform)val.transform;
			RectTransform val5 = (RectTransform)((Component)stackAllButton).transform;
			Vector2 anchoredPosition = val5.anchoredPosition;
			Rect rect = val5.rect;
			val4.anchoredPosition = anchoredPosition + new Vector2(((Rect)(ref rect)).width + 10f, 0f);
			TMP_Text componentInChildren = val.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = "Settings";
			}
			_btn = val.GetComponent<Button>();
			_btn.onClick = new ButtonClickedEvent();
			ButtonClickedEvent onClick = _btn.onClick;
			object obj = <>c.<>9__5_0;
			if (obj == null)
			{
				UnityAction val6 = delegate
				{
					Open = !Open;
				};
				<>c.<>9__5_0 = val6;
				obj = (object)val6;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			((Selectable)_btn).interactable = true;
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverName")]
	internal static class SpecialChestName
	{
		private static void Postfix(Container __instance, ref string __result)
		{
			try
			{
				SpecialChest specialChest = (Object.op_Implicit((Object)(object)__instance) ? ((Component)__instance).GetComponent<SpecialChest>() : null);
				string text = (((Object)(object)specialChest != (Object)null) ? specialChest.CustomName : "");
				if (text.Length > 0)
				{
					__result = text;
				}
			}
			catch (Exception e)
			{
				Safe.Report("SpecialChestName", e);
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "HasFocus")]
	internal static class BlockInput
	{
		private static void Postfix(ref bool __result)
		{
			try
			{
				if (ChestPickerGui.Typing && Plugin.Enabled)
				{
					__result = true;
				}
			}
			catch (Exception e)
			{
				Safe.Report("BlockInput", e);
			}
		}
	}
	internal static class CollectorLogic
	{
		[HarmonyPatch(typeof(Smelter), "Awake")]
		private static class SmelterAwake
		{
			private static void Postfix(Smelter __instance)
			{
				Safe.Run("Reg.Smelter", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate
						{
							Safe.Run("Collect.Smelter", delegate
							{
								if (nv.IsOwner())
								{
									Acc.Smelter_SpawnProcessed(__instance);
								}
							});
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(Smelter), "Spawn")]
		private static class SmelterSpawn
		{
			private static bool Prefix(Smelter __instance, string ore, int stack)
			{
				try
				{
					return PrefixImpl(__instance, ore, stack);
				}
				catch (Exception e)
				{
					Safe.Report("CollectorLogic.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(Smelter __instance, string ore, int stack)
			{
				//IL_0062: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!Cfg.StationChests || (Object)(object)Acc.NView(__instance) == (Object)null || !Acc.NView(__instance).IsOwner() || stack <= 0)
					{
						return true;
					}
					ItemConversion val = Acc.Smelter_GetConversion(__instance, ore);
					if ((Object)(object)val?.m_to == (Object)null)
					{
						return true;
					}
					StationKind kind = Kinds.Of(__instance);
					SpecialChest specialChest = SpecialChest.FindCollectors(((Component)__instance).transform.position, kind).FirstOrDefault();
					if ((Object)(object)specialChest == (Object)null)
					{
						return true;
					}
					Send(specialChest, ((Object)((Component)val.m_to).gameObject).name, stack, Object.op_Implicit((Object)(object)__instance.m_outputPoint) ? __instance.m_outputPoint.position : ((Component)__instance).transform.position, kind);
					Acc.Effects(__instance.m_produceEffects, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation);
					return false;
				}
				catch (Exception e)
				{
					Safe.Report("Smelter.Spawn", e);
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Beehive), "Awake")]
		private static class BeehiveAwake
		{
			private static void Postfix(Beehive __instance)
			{
				Safe.Run("Reg.Beehive", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id)
						{
							//IL_000e: Unknown result type (might be due to invalid IL or missing references)
							//IL_000f: Unknown result type (might be due to invalid IL or missing references)
							Safe.Run("Collect.Beehive", delegate
							{
								//IL_0014: Unknown result type (might be due to invalid IL or missing references)
								//IL_00ab: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
								if (nv.IsOwner())
								{
									SpecialChest specialChest = Resolve(id);
									int num = Acc.Beehive_GetHoneyLevel(__instance);
									if (!((Object)(object)specialChest == (Object)null) && num > 0 && !((Object)(object)__instance.m_honeyItem == (Object)null))
									{
										nv.GetZDO().Set(ZDOVars.s_level, 0, false);
										Acc.Effects(__instance.m_spawnEffect, __instance.m_spawnPoint.position, Quaternion.identity);
										Send(specialChest, ((Object)((Component)__instance.m_honeyItem).gameObject).name, num, __instance.m_spawnPoint.position, StationKind.Beehive);
									}
								}
							});
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(SapCollector), "Awake")]
		private static class SapAwake
		{
			private static void Postfix(SapCollector __instance)
			{
				Safe.Run("Reg.Sap", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id)
						{
							//IL_000e: Unknown result type (might be due to invalid IL or missing references)
							//IL_000f: Unknown result type (might be due to invalid IL or missing references)
							Safe.Run("Collect.Sap", delegate
							{
								//IL_0014: Unknown result type (might be due to invalid IL or missing references)
								//IL_00ab: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
								if (nv.IsOwner())
								{
									SpecialChest specialChest = Resolve(id);
									int num = Acc.Sap_GetLevel(__instance);
									if (!((Object)(object)specialChest == (Object)null) && num > 0 && !((Object)(object)__instance.m_spawnItem == (Object)null))
									{
										nv.GetZDO().Set(ZDOVars.s_level, 0, false);
										Acc.Effects(__instance.m_spawnEffect, __instance.m_spawnPoint.position, Quaternion.identity);
										Send(specialChest, ((Object)((Component)__instance.m_spawnItem).gameObject).name, num, __instance.m_spawnPoint.position, StationKind.SapCollector);
									}
								}
							});
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(Fermenter), "Awake")]
		private static class FermenterAwake
		{
			private static void Postfix(Fermenter __instance)
			{
				Safe.Run("Reg.Fermenter", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id)
						{
							//IL_000e: Unknown result type (might be due to invalid IL or missing references)
							//IL_000f: Unknown result type (might be due to invalid IL or missing references)
							Safe.Run("Collect.Fermenter", delegate
							{
								//IL_0027: Unknown result type (might be due to invalid IL or missing references)
								//IL_002d: Invalid comparison between Unknown and I4
								//IL_0031: Unknown result type (might be due to invalid IL or missing references)
								//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
								//IL_0107: Unknown result type (might be due to invalid IL or missing references)
								//IL_013d: Unknown result type (might be due to invalid IL or missing references)
								if (nv.IsOwner() && (int)Acc.Fermenter_GetStatus(__instance) == 3)
								{
									SpecialChest specialChest = Resolve(id);
									if (!((Object)(object)specialChest == (Object)null))
									{
										string text = Acc.Fermenter_GetContentName(__instance);
										ItemConversion val = Acc.Fermenter_GetConversion(__instance, StringExtensionMethods.GetStableHashCode(text));
										if (!((Object)(object)val?.m_to == (Object)null))
										{
											ZDO zDO = nv.GetZDO();
											zDO.Set(ZDOVars.s_content, "");
											zDO.Set(ZDOVars.s_startTime, 0L);
											Acc.Effects(__instance.m_tapEffects, ((Component)__instance).transform.position, ((Component)__instance).transform.rotation);
											Send(specialChest, ((Object)((Component)val.m_to).gameObject).name, val.m_producedItems, ((Component)__instance).transform.position, StationKind.Fermenter);
										}
									}
								}
							});
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(CookingStation), "Awake")]
		private static class CookingAwake
		{
			private static void Postfix(CookingStation __instance)
			{
				Safe.Run("Reg.Cooking", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						nv.Register<ZDOID>("SoroQoL_Collect", (Action<long, ZDOID>)delegate(long sender, ZDOID id)
						{
							//IL_000e: Unknown result type (might be due to invalid IL or missing references)
							//IL_000f: Unknown result type (might be due to invalid IL or missing references)
							Safe.Run("Collect.Cooking", delegate
							{
								//IL_0014: Unknown result type (might be due to invalid IL or missing references)
								//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
								if (nv.IsOwner())
								{
									SpecialChest specialChest = Resolve(id);
									if (!((Object)(object)specialChest == (Object)null))
									{
										StationKind kind = Kinds.Of(__instance);
										for (int i = 0; i < __instance.m_slots.Length; i++)
										{
											Acc.Cooking_GetSlot(__instance, i, out var item, out var _, out var _, out var _);
											if (!string.IsNullOrEmpty(item) && Acc.Cooking_IsItemDone(__instance, item))
											{
												Acc.Cooking_SetSlot(__instance, i, "", 0f, (Status)0, cheated: false);
												Send(specialChest, item, 1, __instance.m_slots[i].position, kind);
											}
										}
									}
								}
							});
						});
					}
				});
			}
		}

		internal const string RpcCollect = "SoroQoL_Collect";

		public static void Tick(SpecialChest chest)
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Invalid comparison between Unknown and I4
			//IL_01a3: 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_01db: Unknown result type (might be due to invalid IL or missing references)
			ChestMode mode = chest.Mode;
			if (mode == ChestMode.AnimalFeeding || mode == ChestMode.Fuel)
			{
				return;
			}
			Vector3 position = ((Component)chest).transform.position;
			float range = chest.Range;
			ZDOID uid = chest.m_nview.GetZDO().m_uid;
			foreach (Smelter item in SpecialChest.Near<Smelter>(position, range))
			{
				if (Kinds.Matches(mode, Kinds.Of(item)) && Acc.NView(item).GetZDO().GetInt(ZDOVars.s_spawnAmount, 0) > 0)
				{
					Ask(Acc.NView(item), uid);
				}
			}
			foreach (Beehive item2 in SpecialChest.Near<Beehive>(position, range))
			{
				if (Kinds.Matches(mode, StationKind.Beehive) && Acc.Beehive_GetHoneyLevel(item2) > 0)
				{
					Ask(Acc.NView(item2), uid);
				}
			}
			foreach (SapCollector item3 in SpecialChest.Near<SapCollector>(position, range))
			{
				if (Kinds.Matches(mode, StationKind.SapCollector) && Acc.Sap_GetLevel(item3) > 0)
				{
					Ask(Acc.NView(item3), uid);
				}
			}
			foreach (Fermenter item4 in SpecialChest.Near<Fermenter>(position, range))
			{
				if (Kinds.Matches(mode, StationKind.Fermenter) && (int)Acc.Fermenter_GetStatus(item4) == 3)
				{
					Ask(Acc.NView(item4), uid);
				}
			}
			foreach (CookingStation item5 in SpecialChest.Near<CookingStation>(position, range))
			{
				if (Kinds.Matches(mode, Kinds.Of(item5)) && HasDone(item5))
				{
					Ask(Acc.NView(item5), uid);
				}
			}
		}

		private static bool HasDone(CookingStation c)
		{
			for (int i = 0; i < c.m_slots.Length; i++)
			{
				Acc.Cooking_GetSlot(c, i, out var item, out var _, out var _, out var _);
				if (!string.IsNullOrEmpty(item) && Acc.Cooking_IsItemDone(c, item))
				{
					return true;
				}
			}
			return false;
		}

		private static void Ask(ZNetView nv, ZDOID chest)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (SpecialChest.StationReady(nv))
			{
				SpecialChest.MarkStation(nv);
				nv.InvokeRPC("SoroQoL_Collect", new object[1] { chest });
			}
		}

		internal static SpecialChest Resolve(ZDOID id)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.GetComponent<SpecialChest>();
		}

		internal static void Send(SpecialChest chest, string prefab, int amount, Vector3 origin, StationKind kind)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = ItemNet.FromPrefab(prefab, amount);
			if (val != null && amount > 0)
			{
				chest.m_nview.InvokeRPC("SoroQoL_Store", new object[1] { SpecialChest.StorePkg(val, origin, kind, 0) });
			}
		}
	}
	internal static class ConfigSync
	{
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterPatch
		{
			private static void Postfix(ZNetPeer peer)
			{
				try
				{
					PostfixImpl(peer);
				}
				catch (Exception e)
				{
					Safe.Report("ConfigSync.cs:Postfix", e);
				}
			}

			private static void PostfixImpl(ZNetPeer peer)
			{
				Safe.Run("ConfigRegister", delegate
				{
					peer.m_rpc.Register<ZPackage>("SoroQoL_Config", (Action<ZRpc, ZPackage>)Receive);
				});
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private static class SendPatch
		{
			private static void Postfix(ZNet __instance, ZRpc rpc)
			{
				try
				{
					PostfixImpl(__instance, rpc);
				}
				catch (Exception e)
				{
					Safe.Report("ConfigSync.cs:Postfix", e);
				}
			}

			private static void PostfixImpl(ZNet __instance, ZRpc rpc)
			{
				Safe.Run("ConfigSend", delegate
				{
					if (__instance.IsServer())
					{
						rpc.Invoke("SoroQoL_Config", new object[1] { Build() });
					}
				});
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static class ResetPatch
		{
			private static void Postfix()
			{
				_remote.Clear();
				HostVersion = null;
			}
		}

		private const string Rpc = "SoroQoL_Config";

		private static readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>();

		private static readonly Dictionary<ConfigEntryBase, object> _remote = new Dictionary<ConfigEntryBase, object>();

		internal static string HostVersion;

		internal static bool HasHostConfig => _remote.Count > 0;

		internal static void Init(ConfigFile cfg)
		{
			cfg.SettingChanged += delegate
			{
				Safe.Run("ConfigBroadcast", Broadcast);
			};
		}

		internal static void Track(ConfigEntryBase e)
		{
			_entries.Add(e);
		}

		internal static T Get<T>(ConfigEntry<T> e)
		{
			if (_remote.TryGetValue((ConfigEntryBase)(object)e, out var value) && value is T)
			{
				return (T)value;
			}
			return e.Value;
		}

		private static string Key(ConfigEntryBase e)
		{
			return e.Definition.Section + "|" + e.Definition.Key;
		}

		private static ZPackage Build()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write("1.0.21");
			val.Write(_entries.Count);
			foreach (ConfigEntryBase entry in _entries)
			{
				val.Write(Key(entry));
				val.Write(entry.GetSerializedValue());
			}
			return val;
		}

		private static void Broadcast()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer?.m_rpc != null)
				{
					peer.m_rpc.Invoke("SoroQoL_Config", new object[1] { Build() });
				}
			}
		}

		private static void Receive(ZRpc rpc, ZPackage p)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return;
			}
			HostVersion = p.ReadString();
			int num = p.ReadInt();
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			for (int i = 0; i < num; i++)
			{
				dictionary[p.ReadString()] = p.ReadString();
			}
			_remote.Clear();
			foreach (ConfigEntryBase entry in _entries)
			{
				if (dictionary.TryGetValue(Key(entry), out var value))
				{
					try
					{
						_remote[entry] = TomlTypeConverter.ConvertToValue(value, entry.SettingType);
					}
					catch (Exception e)
					{
						Safe.Report("ConfigParse " + Key(entry), e);
					}
				}
			}
			if (HostVersion != "1.0.21")
			{
				Plugin.Log.LogWarning((object)("Host runs Soro's Quality of life mod " + HostVersion + ", you run 1.0.21. Please use the same version."));
			}
			Plugin.Log.LogInfo((object)$"Received {_remote.Count} config values from host.");
		}
	}
	internal static class Cfg
	{
		public const float MinRange = 5f;

		public const float MaxRangeLimit = 30f;

		public static bool StationChests => ConfigSync.Get<bool>(Plugin.EnableStationChests);

		public static float MaxRange => Mathf.Clamp(ConfigSync.Get<float>(Plugin.ChestMaxRange), 5f, 30f);

		public static float Range => Mathf.Clamp(ConfigSync.Get<float>(Plugin.ChestRange), 5f, MaxRange);

		public static float Tick => ConfigSync.Get<float>(Plugin.ChestTickSeconds);

		public static float StationCooldown => ConfigSync.Get<float>(Plugin.StationCooldownSeconds);

		public static int ItemsPerTick => ConfigSync.Get<int>(Plugin.ItemsPerStationPerTick);

		public static bool KilnAllWood => ConfigSync.Get<bool>(Plugin.KilnUseFineAndCoreWood);

		public static bool CookRequireFire => ConfigSync.Get<bool>(Plugin.CookingRequireFire);

		public static bool AnimalFeeding => ConfigSync.Get<bool>(Plugin.EnableAnimalFeeding);

		public static bool FeedTamed => ConfigSync.Get<bool>(Plugin.FeedTamed);

		public static bool FeedWild => ConfigSync.Get<bool>(Plugin.FeedWild);

		public static float AnimalCooldown => ConfigSync.Get<float>(Plugin.AnimalFeedCooldown);

		public static bool FullFood => ConfigSync.Get<bool>(Plugin.EnableFullFood);

		public static bool Recycle => ConfigSync.Get<bool>(Plugin.EnableRecycle);

		public static float RecycleReturn => ConfigSync.Get<float>(Plugin.RecycleReturn);

		public static bool RecycleRequireStation => ConfigSync.Get<bool>(Plugin.RecycleRequireStation);

		public static bool MultiUser => ConfigSync.Get<bool>(Plugin.EnableMultiUser);

		public static int MaxViewers => ConfigSync.Get<int>(Plugin.MaxViewers);

		public static bool Totem => ConfigSync.Get<bool>(Plugin.EnableTotem);

		public static float TotemRadius => ConfigSync.Get<float>(Plugin.TotemRadius);

		public static bool EternalLights => ConfigSync.Get<bool>(Plugin.EnableEternalLights);
	}
	public class CraftingTotem : MonoBehaviour
	{
		[HarmonyPatch(typeof(Container), "Awake")]
		private static class ContainerAwake
		{
			private static void Postfix(Container __instance)
			{
				Safe.Run("Totem.RegContainer", delegate
				{
					ZNetView nv = Acc.NView(__instance);
					if (!((Object)(object)nv == (Object)null) && nv.GetZDO() != null)
					{
						Containers.Add(__instance);
						nv.Register<string, int>("SoroQoL_Take", (Action<long, string, int>)delegate(long sender, string name, int amount)
						{
							Safe.Run("Totem.Take", delegate
							{
								if (nv.IsOwner())
								{
									TakeFrom(__instance.GetInventory(), name, amount, out var _);
								}
							});
						});
						nv.Register<string, int>("SoroQoL_Pull", (Action<long, string, int>)delegate(long sender, string name, int amount)
						{
							Safe.Run("Totem.Pull", delegate
							{
								//IL_0063: Unknown result type (might be due to invalid IL or missing references)
								//IL_0069: Expected O, but got Unknown
								if (nv.IsOwner())
								{
									ItemData proto;
									int num = TakeFrom(__instance.GetInventory(), name, amount, out proto);
									if (num > 0)
									{
										ItemData val = proto.Clone();
										val.m_stack = num;
										if (sender == ZNet.GetUID())
										{
											ItemNet.GiveLocalPlayer(val);
										}
										else
										{
											ZPackage val2 = new ZPackage();
											ItemNet.Write(val2, val);
											ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SoroQoL_MucGive", new object[1] { val2 });
										}
									}
								}
							});
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
		private static class HaveReqItems
		{
			private static void Postfix(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, int amount)
			{
				try
				{
					PostfixImpl(__instance, ref __result, piece, discover, qualityLevel, amount);
				}
				catch (Exception e)
				{
					Safe.Report("CraftingTotem.cs:Postfix", e);
				}
			}

			private static void PostfixImpl(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, int amount)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (__result || discover || (Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null)
					{
						return;
					}
					CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation();
					bool requireOnlyOneIngredient = piece.m_requireOnlyOneIngredient;
					bool flag = false;
					Requirement[] resources = piece.m_resources;
					foreach (Requirement val in resources)
					{
						if (!Applies(val, currentCraftingStation))
						{
							continue;
						}
						int num = val.GetAmount(qualityLevel) * amount;
						if (num <= 0)
						{
							continue;
						}
						string name = val.m_resItem.m_itemData.m_shared.m_name;
						bool flag2 = ((Humanoid)__instance).GetInventory().CountItems(name, -1, true) + CountInSources(__instance, name) >= num;
						if (requireOnlyOneIngredient)
						{
							if (flag2)
							{
								flag = true;
								break;
							}
						}
						else if (!flag2)
						{
							Diag(piece, name, num, __instance);
							return;
						}
					}
					if (!requireOnlyOneIngredient || flag)
					{
						__result = true;
					}
				}
				catch (Exception e)
				{
					Safe.Report("Totem.HaveReqItems", e);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		private static class HaveReqPiece
		{
			private static void Postfix(Player __instance, ref bool __result, Piece piece, RequirementMode mode)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					PostfixImpl(__instance, ref __result, piece, mode);
				}
				catch (Exception e)
				{
					Safe.Report("CraftingTotem.cs:Postfix", e);
				}
			}

			private static void PostfixImpl(Player __instance, ref bool __result, Piece piece, RequirementMode mode)
			{
				//IL_0004: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (__result || (int)mode != 0 || (Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null || (Object.op_Implicit((Object)(object)piece.m_craftingStation) && !Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position))))
					{
						return;
					}
					Requirement[] resources = piece.m_resources;
					foreach (Requirement val in resources)
					{
						if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0)
						{
							string name = val.m_resItem.m_itemData.m_shared.m_name;
							if (((Humanoid)__instance).GetInventory().CountItems(name, -1, true) + CountInSources(__instance, name) < val.m_amount)
							{
								return;
							}
						}
					}
					__result = true;
				}
				catch (Exception e)
				{
					Safe.Report("Totem.HaveReqPiece", e);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
		private static class ShowCounts
		{
			private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier)
			{
				try
				{
					PostfixImpl(elementRoot, req, player, quality, craftMultiplier);
				}
				catch (Exception e)
				{
					Safe.Report("CraftingTotem.cs:Postfix", e);
				}
			}

			private static void PostfixImpl(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)req?.m_resItem == (Object)null || (Object)(object)player == (Object)null || (Object)(object)Covering(((Component)player).transform.position) == (Object)null)
					{
						return;
					}
					Transform obj = elementRoot.Find("res_amount");
					TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
					if (!((Object)(object)val == (Object)null))
					{
						string name = req.m_resItem.m_itemData.m_shared.m_name;
						int num = req.GetAmount(quality) * craftMultiplier;
						int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true) + CountInSources(player, name);
						if (num > 0)
						{
							val.text = $"{num2}/{num}";
						}
						if (num2 >= num)
						{
							((Graphic)val).color = Color.white;
						}
					}
				}
				catch (Exception e)
				{
					Safe.Report("Totem.ShowCounts", e);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static class Consume
		{
			private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int multiplier)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (requirements == null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || __instance.NoCostCheat() || (Object)(object)Covering(((Component)__instance).transform.position) == (Object)null)
					{
						return;
					}
					Inventory inventory = ((Humanoid)__instance).GetInventory();
					CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation();
					foreach (Requirement val in requirements)
					{
						if (Applies(val, currentCraftingStation))
						{
							int num = val.GetAmount(qualityLevel) * Mathf.Max(1, multiplier);
							string name = val.m_resItem.m_itemData.m_shared.m_name;
							int num2 = num - inventory.CountItems(name, -1, true);
							if (num2 > 0)
							{
								TakeFromChests(__instance, name, num2);
							}
						}
					}
				}
				catch (Exception e)
				{
					Safe.Report("Totem.Consume", e);
				}
			}
		}

		internal static readonly List<CraftingTotem> All = new List<CraftingTotem>();

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

		private const string RpcPull = "SoroQoL_Pull";

		private static readonly HashSet<string> _diag = new HashSet<string>();

		private const string RpcTake = "SoroQoL_Take";

		private void Awake()
		{
			ZNetView component = ((Component)this).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.GetZDO() != null)
			{
				All.Add(this);
			}
		}

		private void OnDestroy()
		{
			All.Remove(this);
		}

		internal static CraftingTotem Covering(Vector3 pos)
		{
			//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)
			if (!Cfg.Totem)
			{
				return null;
			}
			float r = Cfg.TotemRadius;
			return All.FirstOrDefault((CraftingTotem t) => Object.op_Implicit((Object)(object)t) && Vector3.Distance(((Component)t).transform.position, pos) <= r);
		}

		internal static List<Container> Sources(Player pl)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			if ((Object)(object)pl == (Object)null)
			{
				return list;
			}
			CraftingTotem craftingTotem = Covering(((Component)pl).transform.position);
			if ((Object)(object)craftingTotem == (Object)null)
			{
				return list;
			}
			float totemRadius = Cfg.TotemRadius;
			long playerID = pl.GetPlayerID();
			Containers.RemoveAll((Container c) => (Object)(object)c == (Object)null);
			foreach (Container container in Containers)
			{
				ZNetView val = Acc.NView(container);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && container.GetInventory() != null && !(Vector3.Distance(((Component)container).transform.position, ((Component)craftingTotem).transform.position) > totemRadius) && !((Object)(object)container.m_wagon != (Object)null) && !((Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null))
				{
					Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
					if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsPlacedByPlayer() && Acc.Container_CheckAccess(container, playerID) && PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false))
					{
						list.Add(container);
					}
				}
			}
			return list.OrderBy((Container c) => Vector3.Distance(((Component)c).transform.position, ((Component)pl).transform.position)).ToList();
		}

		internal static int CountInSources(Player pl, string name)
		{
			return Sources(pl).Sum((Container c) => c.GetInventory().CountItems(name, -1, true));
		}

		internal static bool Applies(Requirement req, CraftingStation station)
		{
			if ((Object)(object)req?.m_resItem == (Object)null)
			{
				return false;
			}
			bool flag = Acc.IsUpgraderResource(req);
			if (!((Object)(object)station != (Object)null))
			{
				return !flag;
			}
			return Acc.StationIsUpgrader(station) == flag;
		}

		private static void Diag(Recipe r, string n, int need, Player pl)
		{
			string text = (Object.op_Implicit((Object)(object)r.m_item) ? ((Object)r.m_item).name : "?") + "|" + n;
			if (_diag.Add(text))
			{
				Plugin.Log.LogInfo((object)$"[Totem] {text}: need {need}, inventory {((Humanoid)pl).GetInventory().CountItems(n, -1, true)}, chests {CountInSources(pl, n)}");
			}
		}

		internal static int TakeFromChests(Player pl, string name, int amount)
		{
			if (amount <= 0)
			{
				return 0;
			}
			List<Container> source = Sources(pl);
			int num = amount;
			foreach (Container item in source.Where((Container c) => Acc.NView(c).IsOwner()))
			{
				if (num <= 0)
				{
					break;
				}
				num -= TakeFrom(item.GetInventory(), name, num, out var _);
			}
			foreach (Container item2 in source.Where((Container c) => !Acc.NView(c).IsOwner()))
			{
				if (num <= 0)
				{
					break;
				}
				int num2 = Mathf.Min(num, item2.GetInventory().CountItems(name, -1, true));
				if (num2 > 0)
				{
					Acc.NView(item2).InvokeRPC("SoroQoL_Take", new object[2] { name, num2 });
					num -= num2;
				}
			}
			return amount - num;
		}

		private static int TakeFrom(Inventory inv, string name, int amount, out ItemData proto)
		{
			proto = null;
			int num = 0;
			foreach (ItemData item in (from i in inv.GetAllItems()
				where i.m_shared.m_name == name
				select i).ToList())
			{
				if (num >= amount)
				{
					break;
				}
				int num2 = Mathf.Min(item.m_stack, amount - num);
				proto = proto ?? item.Clone();
				if (inv.RemoveItem(item, num2))
				{
					num += num2;
				}
			}
			return num;
		}
	}
	internal static class EternalLights
	{
		[HarmonyPatch(typeof(Fireplace), "UpdateFireplace")]
		private static class Patch
		{
			private static void Prefix(Fireplace __instance)
			{
				try
				{
					Impl(__instance);
				}
				catch (Exception e)
				{
					Safe.Report("EternalLights", e);
				}
			}

			private static void Impl(Fireplace f)
			{
				if (!Cfg.EternalLights || (Object)(object)f == (Object)null || f.m_infiniteFuel)
				{
					return;
				}
				ZNetView val = Acc.NView(f);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && IsLight(f))
				{
					ZDO zDO = val.GetZDO();
					if (zDO.GetFloat(ZDOVars.s_fuel, 0f) < f.m_maxFuel)
					{
						zDO.Set(ZDOVars.s_fuel, f.m_maxFuel);
					}
				}
			}
		}

		private static readonly HashSet<string> Known = new HashSet<string>
		{
			"piece_groundtorch", "piece_groundtorch_wood", "piece_groundtorch_green", "piece_groundtorch_blue", "piece_groundtorch_mist", "piece_walltorch", "piece_brazierceiling01", "piece_brazierfloor01", "piece_brazierfloor02", "piece_jackoturnip",
			"piece_dvergr_lantern", "piece_dvergr_lantern_pole", "piece_dvergr_wood_lantern", "CandleSconce", "Candle_resin", "piece_Lantern", "piece_lantern", "piece_sconce", "piece_groundtorch_flaming", "piece_brazier_charred",
			"piece_charred_torch"
		};

		private static readonly string[] Words = new string[7] { "torch", "sconce", "brazier", "lantern", "lamp", "candle", "jackoturnip" };

		private static readonly string[] NotLights = new string[11]
		{
			"fire_pit", "firepit", "hearth", "bonfire", "cooking", "oven", "kiln", "smelter", "furnace", "bathtub",
			"hottub"
		};

		private static readonly Dictionary<string, bool> _cache = new Dictionary<string, bool>();

		public static bool IsLight(Fireplace f)
		{
			if ((Object)(object)f == (Object)null)
			{
				return false;
			}
			string prefabName = Utils.GetPrefabName(((Component)f).gameObject);
			if (_cache.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			value = Classify(f, prefabName);
			_cache[prefabName] = value;
			return value;
		}

		private static bool Classify(Fireplace f, string name)
		{
			if (Known.Contains(name))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)((Component)f).GetComponent<CookingStation>()) || Object.op_Implicit((Object)(object)((Component)f).GetComponentInParent<Smelter>()))
			{
				return false;
			}
			string text = name.ToLowerInvariant();
			string[] notLights = NotLights;
			foreach (string value in notLights)
			{
				if (text.Contains(value))
				{
					return false;
				}
			}
			notLights = Words;
			foreach (string value2 in notLights)
			{
				if (text.Contains(value2))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class FeederLogic
	{
		public static void Tick(SpecialChest chest)
		{
			//IL_0045: 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_0085: 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)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			Inventory inv = chest.m_container.GetInventory();
			if (inv == null || inv.GetAllItems().Count == 0)
			{
				return;
			}
			ChestMode mode = chest.Mode;
			Vector3 pos = ((Component)chest).transform.position;
			float range = chest.Range;
			if (mode == ChestMode.AnimalFeeding)
			{
				if (Cfg.AnimalFeeding)
				{
					AnimalFeeder.Tick(chest, inv);
				}
				return;
			}
			bool fuelOnly = mode == ChestMode.Fuel;
			foreach (Smelter s in from x in SpecialChest.Near<Smelter>(pos, range)
				orderby Vector3.Distance(((Component)x).transform.position, pos)
				select x)
			{
				Safe.Run("Feeder.Smelter", delegate
				{
					FeedSmelter(s, inv, mode, fuelOnly);
				});
			}
			foreach (CookingStation c in from x in SpecialChest.Near<CookingStation>(pos, range)
				orderby Vector3.Distance(((Component)x).transform.position, pos)
				select x)
			{
				Safe.Run("Feeder.Cooking", delegate
				{
					FeedCooking(c, inv, mode, fuelOnly);
				});
			}
			if (!fuelOnly)
			{
				foreach (Fermenter f in SpecialChest.Near<Fermenter>(pos, range))
				{
					Safe.Run("Feeder.Fermenter", delegate
					{
						FeedFermenter(f, inv, mode);
					});
				}
			}
			foreach (Fireplace f2 in SpecialChest.Near<Fireplace>(pos, range))
			{
				Safe.Run("Feeder.Fire", delegate
				{
					FeedFire(f2, inv, mode, fuelOnly);
				});
			}
		}

		private static ItemData Find(Inventory inv, ItemDrop prefabItem)
		{
			if ((Object)(object)prefabItem == (Object)null)
			{
				return null;
			}
			string n = prefabItem.m_itemData.m_shared.m_name;
			return ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == n && i.m_stack > 0));
		}

		private static bool IsOutputOf(Smelter s, ItemData x)
		{
			string name = x.m_shared.m_name;
			foreach (ItemConversion item in s.m_conversion)
			{
				if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsOutputOf(CookingStation s, ItemData x)
		{
			string name = x.m_shared.m_name;
			if ((Object)(object)s.m_overCookedItem != (Object)null && s.m_overCookedItem.m_itemData.m_shared.m_name == name)
			{
				return true;
			}
			foreach (ItemConversion item in s.m_conversion)
			{
				if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name)
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsOutputOf(Fermenter s, ItemData x)
		{
			string name = x.m_shared.m_name;
			foreach (ItemConversion item in s.m_conversion)
			{
				if ((Object)(object)item?.m_to != (Object)null && item.m_to.m_itemData.m_shared.m_name == name)
				{
					return true;
				}
			}
			return false;
		}

		private static bool Push(Inventory inv, ItemData it, ZNetView nv, Func<float> probe, Action send)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (it == null || (Object)(object)nv == (Object)null || !nv.IsValid() || !nv.IsOwner())
			{
				return false;
			}
			float num = probe();
			ItemData val = it.Clone();
			val.m_stack = 1;
			if (!inv.RemoveItem(it, 1))
			{
				return false;
			}
			bool flag = false;
			try
			{
				send();
				flag = Mathf.Abs(probe() - num) > 0.0001f;
			}
			catch (Exception e)
			{
				Safe.Report("Feeder.Push", e);
			}
			if (!flag)
			{
				int num2 = ItemNet.AddAsMuch(inv, val);
				if (num2 > 0)
				{
					ItemNet.Drop(val, num2, ((Component)nv).transform.position);
				}
			}
			return flag;
		}

		private static float SlotsUsed(CookingStation c)
		{
			int num = 0;
			for (int i = 0; i < c.m_slots.Length; i++)
			{
				Acc.Cooking_GetSlot(c, i, out var item, out var _, out var _, out var _);
				if (!string.IsNullOrEmpty(item))
				{
					num++;
				}
			}
			return num;
		}

		private static bool TakeOne(Inventory inv, ItemData it)
		{
			if (it != null)
			{
				return inv.RemoveItem(it, 1);
			}
			return false;
		}

		private static void FeedSmelter(Smelter s, Inventory inv, ChestMode mode, bool fuelOnly)
		{
			ZNetView nv = Acc.NView(s);
			StationKind kind = Kinds.Of(s);
			if ((!fuelOnly && !Kinds.Matches(mode, kind)) || !SpecialChest.StationReady(nv))
			{
				return;
			}
			bool flag = false;
			int itemsPerTick = Cfg.ItemsPerTick;
			if ((Object)(object)s.m_fuelItem != (Object)null)
			{
				int num = s.m_maxFuel - Mathf.CeilToInt(Acc.Smelter_GetFuel(s));
				for (int i = 0; i < Mathf.Min(num, itemsPerTick); i++)
				{
					ItemData it = Find(inv, s.m_fuelItem);
					if (!Push(inv, it, nv, () => Acc.Smelter_GetFuel(s), delegate
					{
						nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
					}))
					{
						break;
					}
					flag = true;
				}
			}
			if (!fuelOnly && kind != StationKind.HotTub)
			{
				int num2 = s.m_maxOre - Acc.Smelter_GetQueueSize(s);
				for (int num3 = 0; num3 < Mathf.Min(num2, itemsPerTick); num3++)
				{
					ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Smelter_IsItemAllowed(s, x) && !IsOutputOf(s, x) && (kind != StationKind.Kiln || Cfg.KilnAllWood || (!(((Object)x.m_dropPrefab).name == "FineWood") && !(((Object)x.m_dropPrefab).name == "RoundLog")))));
					if (val == null)
					{
						break;
					}
					string prefab = ((Object)val.m_dropPrefab).name;
					if (!Push(inv, val, nv, () => Acc.Smelter_GetQueueSize(s), delegate
					{
						nv.InvokeRPC("RPC_AddOre", new object[2] { prefab, false });
					}))
					{
						break;
					}
					flag = true;
				}
			}
			if (flag)
			{
				SpecialChest.MarkStation(nv);
			}
		}

		private static void FeedCooking(CookingStation c, Inventory inv, ChestMode mode, bool fuelOnly)
		{
			ZNetView nv = Acc.NView(c);
			StationKind k = Kinds.Of(c);
			if ((!fuelOnly && !Kinds.Matches(mode, k)) || !SpecialChest.StationReady(nv))
			{
				return;
			}
			bool flag = false;
			if (c.m_useFuel && (Object)(object)c.m_fuelItem != (Object)null)
			{
				int num = c.m_maxFuel - Mathf.CeilToInt(Acc.Cooking_GetFuel(c));
				for (int i = 0; i < Mathf.Min(num, Cfg.ItemsPerTick); i++)
				{
					if (!Push(inv, Find(inv, c.m_fuelItem), nv, () => Acc.Cooking_GetFuel(c), delegate
					{
						nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
					}))
					{
						break;
					}
					flag = true;
				}
			}
			if (!fuelOnly && (!Cfg.CookRequireFire || !c.m_requireFire || Acc.Cooking_IsFireLit(c)))
			{
				int num2 = 0;
				for (int num3 = 0; num3 < c.m_slots.Length; num3++)
				{
					Acc.Cooking_GetSlot(c, num3, out var item, out var _, out var _, out var _);
					if (string.IsNullOrEmpty(item))
					{
						num2++;
					}
				}
				for (int num4 = 0; num4 < num2; num4++)
				{
					ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Cooking_IsItemAllowed(c, x) && !IsOutputOf(c, x)));
					if (val == null)
					{
						break;
					}
					string prefab = ((Object)val.m_dropPrefab).name;
					if (!Push(inv, val, nv, () => SlotsUsed(c), delegate
					{
						nv.InvokeRPC("RPC_AddItem", new object[2] { prefab, false });
					}))
					{
						break;
					}
					flag = true;
				}
			}
			if (flag)
			{
				SpecialChest.MarkStation(nv);
			}
		}

		private static void FeedFermenter(Fermenter f, Inventory inv, ChestMode mode)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!Kinds.Matches(mode, StationKind.Fermenter))
			{
				return;
			}
			ZNetView nv = Acc.NView(f);
			if (!SpecialChest.StationReady(nv) || (int)Acc.Fermenter_GetStatus(f) != 0)
			{
				return;
			}
			ItemData val = ((IEnumerable<ItemData>)inv.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_stack > 0 && (Object)(object)x.m_dropPrefab != (Object)null && Acc.Fermenter_IsItemAllowed(f, x) && !IsOutputOf(f, x)));
			if (val != null)
			{
				int hash = StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name);
				if (Push(inv, val, nv, () => (float)Acc.Fermenter_GetStatus(f), delegate
				{
					nv.InvokeRPC("RPC_AddItem", new object[2] { hash, false });
				}))
				{
					SpecialChest.MarkStation(nv);
				}
			}
		}

		private static void FeedFire(Fireplace f, Inventory inv, ChestMode mode, bool fuelOnly)
		{
			if ((EternalLights.IsLight(f) && Cfg.EternalLights) || (!fuelOnly && !Kinds.Matches(mode, StationKind.Fire)) || f.m_infiniteFuel || !f.m_canRefill || (Object)(object)f.m_fuelItem == (Object)null)
			{
				return;
			}
			ZNetView nv = Acc.NView(f);
			if (!SpecialChest.StationReady(nv))
			{
				return;
			}
			float num = nv.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
			int num2 = Mathf.FloorToInt(f.m_maxFuel - num);
			bool flag = false;
			for (int i = 0; i < Mathf.Min(num2, Cfg.ItemsPerTick); i++)
			{
				if (!Push(inv, Find(inv, f.m_fuelItem), nv, () => nv.GetZDO().GetFloat(ZDOVars.s_fuel, 0f), delegate
				{
					nv.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}))
				{
					break;
				}
				flag = true;
			}
			if (flag)
			{
				SpecialChest.MarkStation(nv);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
	internal static class FullFoodPatch
	{
		private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			try
			{
				PostfixImpl(__instance, ref hp, ref stamina, ref eitr);
			}
			catch (Exception e)
			{
				Safe.Report("FullFood.cs:Postfix", e);
			}
		}

		private static void PostfixImpl(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			try
			{
				List<Food> list = (((Object)(object)__instance == (Object)null) ? null : Acc.Player_foods.Invoke(__instance));
				if (!Cfg.FullFood || list == null)
				{
					return;
				}
				float num = 0f;
				float num2 = 0f;
				float num3 = 0f;
				foreach (Food item in list)
				{
					SharedData val = item?.m_item?.m_shared;
					if (val != null && !(item.m_time <= 0f))
					{
						num += Math.Max(0f, val.m_food - item.m_health);
						num2 += Math.Max(0f, val.m_foodStamina - item.m_stamina);
						num3 += Math.Max(0f, val.m_foodEitr - item.m_eitr);
					}
				}
				hp += num;
				stamina += num2;
				eitr += num3;
			}
			catch (Exception e)
			{
				Safe.Report("FullFood", e);
			}
		}
	}
	internal static class ItemNet
	{
		public static void Write(ZPackage p, ItemData it)
		{
			p.Write(Object.op_Implicit((Object)(object)it.m_dropPrefab) ? ((Object)it.m_dropPrefab).name : "");
			p.Write(it.m_stack);
			p.Write(it.m_quality);
			p.Write(it.m_variant);
			p.Write(it.m_durability);
			p.Write(it.m_crafterID);
			p.Write(it.m_crafterName ?? "");
			p.Write(it.m_worldLevel);
			p.Write(it.m_customData?.Count ?? 0);
			if (it.m_customData == null)
			{
				return;
			}
			foreach (KeyValuePair<string, string> customDatum in it.m_customData)
			{
				p.Write(customDatum.Key);
				p.Write(customDatum.Value);
			}
		}

		public static ItemData Read(ZPackage p)
		{
			string text = p.ReadString();
			int stack = p.ReadInt();
			int quality = p.ReadInt();
			int variant = p.ReadInt();
			float durability = p.ReadSingle();
			long crafterID = p.ReadLong();
			string crafterName = p.ReadString();
			int worldLevel = p.ReadInt();
			int num = p.ReadInt();
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			for (int i = 0; i < num; i++)
			{
				dictionary[p.ReadString()] = p.ReadString();
			}
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(text) : null);
			ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Unknown item prefab in RPC: " + text));
				return null;
			}
			ItemData obj = val2.m_itemData.Clone();
			obj.m_dropPrefab = val;
			obj.m_stack = stack;
			obj.m_quality = quality;
			obj.m_variant = variant;
			obj.m_durability = durability;
			obj.m_crafterID = crafterID;
			obj.m_crafterName = crafterName;
			obj.m_worldLevel = worldLevel;
			obj.m_customData = dictionary;
			return obj;
		}

		public static ItemData FromPrefab(string prefabName, int stack)
		{
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(prefabName) : null);
			ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			ItemData obj = val2.m_itemData.Clone();
			obj.m_dropPrefab = val;
			obj.m_stack = stack;
			return obj;
		}

		public static int AddAsMuch(Inventory inv, ItemData item)
		{
			int num = item.m_stack;
			int num2 = Mathf.Max(1, item.m_shared.m_maxStackSize);
			while (num > 0)
			{
				int num3 = Mathf.Min(num, num2);
				ItemData val = item.Clone();
				val.m_stack = num3;
				if (inv.CanAddItem(val, num3) && inv.AddItem(val))
				{
					num -= num3;
					continue;
				}
				ItemData val2 = item.Clone();
				val2.m_stack = 1;
				if (!inv.CanAddItem(val2, 1) || !inv.AddItem(val2))
				{
					break;
				}
				num--;
			}
			return num;
		}

		public static void Drop(ItemData item, int amount, Vector3 pos)
		{
			//IL_000a: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (item != null && amount > 0)
			{
				ItemDrop.DropItem(item, amount, pos + Vector3.up, Quaternion.identity);
			}
		}

		public static void GiveLocalPlayer(ItemData item)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && item != null)
			{
				int num = AddAsMuch(((Humanoid)localPlayer).GetInventory(), item);
				if (num > 0)
				{
					Drop(item, num, ((Component)localPlayer).transform.position);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
	internal static class LegacyChests
	{
		private static readonly int FeederHash = StringExtensionMethods.GetStableHashCode("soro_feeder_chest");

		private static readonly int CollectorHash = StringExtensionMethods.GetStableHashCode("soro_collector_chest");

		private static readonly int ProductionHash = StringExtensionMethods.GetStableHashCode("soro_production_chest");

		internal static readonly Dictionary<ZDOID, bool> Pending = new Dictionary<ZDOID, bool>();

		internal static void Apply(ZDO zdo)
		{
			//IL_0015: 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)
			if (zdo == null || Pending.Count == 0 || !Pending.TryGetValue(zdo.m_uid, out var value) || !zdo.IsOwner())
			{
				return;
			}
			Pending.Remove(zdo.m_uid);
			int num = default(int);
			if (!zdo.GetInt("soro_role", ref num))
			{
				zdo.Set("soro_role", (!value) ? 1 : 0);
				if (value)
				{
					zdo.Set("soro_paused", 1);
				}
				if (!value && SpecialChest.InputOnly((ChestMode)zdo.GetInt("soro_mode", 0)))
				{
					zdo.Set("soro_mode", 0);
				}
			}
		}

		private static void Prefix(ZDO zdo)
		{
			try
			{
				PrefixImpl(zdo);
			}
			catch (Exception e)
			{
				Safe.Report("LegacyChests.cs:Prefix", e);
			}
		}

		private static void PrefixImpl(ZDO zdo)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null)
			{
				return;
			}
			int prefab = zdo.GetPrefab();
			if (prefab == FeederHash || prefab == CollectorHash)
			{
				bool flag = prefab == FeederHash;
				zdo.SetPrefab(ProductionHash);
				int num = default(int);
				if (!zdo.GetInt("soro_role", ref num))
				{
					Pending[zdo.m_uid] = flag;
				}
				Apply(zdo);
				Plugin.Log.LogInfo((object)("Converted old " + (flag ? "Feeder" : "Collector") + " chest to Production Chest (" + (flag ? "Input" : "Output") + ")"));
			}
		}
	}
	internal static class MultiUserChest
	{
		[HarmonyPatch(typeof(Container), "Awake")]
		private static class ContainerAwake
		{
			private static void Postfix(Container __instance)
			{
				Safe.Run("MUC.Reg", delegate
				{
					ZNetView val = Acc.NView(__instance);
					if (!((Object)(object)val == (Object)null) && val.GetZDO() != null)
					{
						val.Register<bool>("SoroQoL_MucView", (Action<long, bool>)delegate(long s, bool open)
						{
							OnView(__instance, s, open);
						});
						val.Register<int, int, int, string>("SoroQoL_MucTake", (Method<int, int, int, string>)delegate(long s, int x, int y, int n, string prefab)
						{
							OnTake(__instance, s, x, y, n, prefab);
						});
						val.Register<int, int, ZPackage>("SoroQoL_MucPut", (Action<long, int, int, ZPackage>)delegate(long s, int x, int y, ZPackage pkg)
						{
							OnPut(__instance, s, x, y, pkg);
						});
					}
				});
			}
		}

		[HarmonyPatch(typeof(Game), "Start")]
		private static class GameStart
		{
			private static void Postfix()
			{
				Safe.Run("MUC.RegGive", delegate
				{
					ZRoutedRpc.instance.Register<ZPackage>("SoroQoL_MucGive", (Action<long, ZPackage>)delegate(long s, ZPackage pkg)
					{
						Safe.Run("MUC.Give", delegate
						{
							ItemNet.GiveLocalPlayer(ItemNet.Read(pkg));
						});
					});
				});
			}
		}

		[HarmonyPatch(typeof(Container), "RPC_RequestOpen")]
		private static class RequestOpen
		{
			private static bool Prefix(Container __instance, long uid, long playerID)
			{
				try
				{
					return PrefixImpl(__instance, uid, playerID);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(Container __instance, long uid, long playerID)
			{
				try
				{
					if (!On || !Acc.NView(__instance).IsOwner())
					{
						return true;
					}
					if (!Acc.Container_CheckAccess(__instance, playerID))
					{
						return true;
					}
					if ((!__instance.IsInUse() && (!Object.op_Implicit((Object)(object)__instance.m_wagon) || !__instance.m_wagon.InUse())) || uid == ZNet.GetUID())
					{
						return true;
					}
					bool flag = 1 + ActiveViewers(__instance, uid) < Mathf.Max(1, Cfg.MaxViewers);
					if (flag)
					{
						OnView(__instance, uid, open: true);
					}
					Acc.NView(__instance).InvokeRPC(uid, "RPC_OpenResponse", new object[1] { flag });
					return false;
				}
				catch (Exception e)
				{
					Safe.Report("MUC.Open", e);
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "SetInUse")]
		private static class SetInUse
		{
			private static bool Prefix(Container __instance)
			{
				try
				{
					return PrefixImpl(__instance);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(Container __instance)
			{
				try
				{
					return !On || (Object)(object)Acc.NView(__instance) == (Object)null || !Acc.NView(__instance).IsValid() || Acc.NView(__instance).IsOwner();
				}
				catch (Exception e)
				{
					Safe.Report("MUC.SetInUse", e);
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class UpdateContainer
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> ins)
			{
				MethodInfo isOwner = AccessTools.Method(typeof(Container), "IsOwner", (Type[])null, (Type[])null);
				MethodInfo repl = AccessTools.Method(typeof(UpdateContainer), "CanView", (Type[])null, (Type[])null);
				foreach (CodeInstruction @in in ins)
				{
					if ((@in.opcode == OpCodes.Callvirt || @in.opcode == OpCodes.Call) && @in.operand as MethodInfo == isOwner)
					{
						yield return new CodeInstruction(OpCodes.Call, (object)repl);
					}
					else
					{
						yield return @in;
					}
				}
			}

			private static bool SafeIsOwner(Container c)
			{
				try
				{
					return c.IsOwner();
				}
				catch
				{
					return false;
				}
			}

			private static bool CanViewImpl(Container c)
			{
				if (!c.IsOwner())
				{
					if (On && (Object)(object)Acc.NView(c) != (Object)null)
					{
						return Acc.NView(c).IsValid();
					}
					return false;
				}
				return true;
			}

			public static bool CanView(Container c)
			{
				try
				{
					return CanViewImpl(c);
				}
				catch (Exception e)
				{
					Safe.Report("MUC.CanView", e);
					return SafeIsOwner(c);
				}
			}

			private static void Postfix(InventoryGui __instance)
			{
				Safe.Run("MUC.Update", delegate
				{
					Container val = Acc.CurrentContainer(__instance);
					if (On && !((Object)(object)val == (Object)null) && !((Object)(object)Acc.NView(val) == (Object)null) && Acc.NView(val).IsValid() && !val.IsOwner())
					{
						Acc.Container_CheckForChanges(val);
						if (Time.time >= _nextPing)
						{
							_nextPing = Time.time + 2f;
							Acc.NView(val).InvokeRPC("SoroQoL_MucView", new object[1] { true });
						}
					}
				});
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
		private static class Close
		{
			private static void Prefix(InventoryGui __instance)
			{
				Safe.Run("MUC.Close", delegate
				{
					Container val = Acc.CurrentContainer(__instance);
					if (On && (Object)(object)val != (Object)null && (Object)(object)Acc.NView(val) != (Object)null && Acc.NView(val).IsValid() && !val.IsOwner())
					{
						Acc.NView(val).InvokeRPC("SoroQoL_MucView", new object[1] { false });
					}
				});
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		private static class Selected
		{
			private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0004: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					return PrefixImpl(__instance, grid, item, pos, mod);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod)
			{
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Invalid comparison between Unknown and I4
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_0148: Invalid comparison between Unknown and I4
				try
				{
					if (!Viewing(__instance, out var c))
					{
						return true;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null)
					{
						return true;
					}
					Inventory inventory = ((Humanoid)localPlayer).GetInventory();
					bool flag = (Object)(object)grid == (Object)(object)Acc.Gui_containerGrid.Invoke(__instance);
					ItemData val = Acc.Gui_dragItem.Invoke(__instance);
					if (flag && val == null && item != null)
					{
						int num = (((int)mod == 1) ? Mathf.Max(1, item.m_stack / 2) : item.m_stack);
						Acc.NView(c).InvokeRPC("SoroQoL_MucTake", new object[4]
						{
							item.m_gridPos.x,
							item.m_gridPos.y,
							num,
							Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : ""
						});
						return false;
					}
					if (flag && val != null && Acc.Gui_dragInventory.Invoke(__instance) == inventory)
					{
						SendPut(c, localPlayer, val, Acc.Gui_dragAmount.Invoke(__instance), pos.x, pos.y);
						Acc.Gui_SetupDragItem(__instance, null, null, 1);
						return false;
					}
					if (!flag && val == null && item != null && (int)mod == 2)
					{
						SendPut(c, localPlayer, item, item.m_stack, -1, -1);
						return false;
					}
					if (val != null && Acc.Gui_dragInventory.Invoke(__instance) == c.GetInventory())
					{
						Acc.Gui_SetupDragItem(__instance, null, null, 1);
						return false;
					}
					return true;
				}
				catch (Exception e)
				{
					Safe.Report("MUC.Select", e);
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
		private static class RightClick
		{
			private static bool Prefix(InventoryGui __instance, InventoryGrid grid)
			{
				try
				{
					return PrefixImpl(__instance, grid);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(InventoryGui __instance, InventoryGrid grid)
			{
				try
				{
					Container c;
					return !Viewing(__instance, out c) || !((Object)(object)grid == (Object)(object)Acc.Gui_containerGrid.Invoke(__instance));
				}
				catch (Exception e)
				{
					Safe.Report("MUC.RightClick", e);
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnTakeAll")]
		private static class TakeAll
		{
			private static bool Prefix(InventoryGui __instance)
			{
				try
				{
					return PrefixImpl(__instance);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(InventoryGui __instance)
			{
				Container c;
				try
				{
					if (!Viewing(__instance, out c))
					{
						return true;
					}
				}
				catch (Exception e)
				{
					Safe.Report("MUC.TakeAll", e);
					return true;
				}
				Safe.Run("MUC.TakeAll", delegate
				{
					foreach (ItemData item in c.GetInventory().GetAllItems().ToList())
					{
						Acc.NView(c).InvokeRPC("SoroQoL_MucTake", new object[4]
						{
							item.m_gridPos.x,
							item.m_gridPos.y,
							item.m_stack,
							Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : ""
						});
					}
				});
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnStackAll")]
		private static class StackAll
		{
			private static bool Prefix(InventoryGui __instance)
			{
				try
				{
					return PrefixImpl(__instance);
				}
				catch (Exception e)
				{
					Safe.Report("MultiUserChest.cs:Prefix", e);
					return true;
				}
			}

			private static bool PrefixImpl(InventoryGui __instance)
			{
				try
				{
					if (!Viewing(__instance, out var _))
					{
						return true;
					}
				}
				catch (Exception e)
				{
					Safe.Report("MUC.StackAll", e);
					return true;
				}
				Acc.Msg("Stack-all is only available to the first player using this chest.");
				return false;
			}
		}

		private const string RpcView = "SoroQoL_MucView";

		private const string RpcTake = "SoroQoL_MucTake";

		private const string RpcPut = "SoroQoL_MucPut";

		private const string RpcGive = "SoroQoL_MucGive";

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

		private static float _nextPing;

		private static bool On => Cfg.MultiUser;

		private static bool IsSpecialOrNormal(Container c)
		{
			if ((Object)(object)c != (Object)null && (Object)(object)Acc.NView(c) != (Object)null)
			{
				return Acc.NView(c).IsValid();
			}
			return false;
		}

		private static int ActiveViewers(Container c, long except)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!_viewers.TryGetValue(Acc.NView(c).GetZDO().m_uid, out var value))
			{
				return 0;
			}
			float now = Time.time;
			foreach (long item in (from kv in value
				where now - kv.Value > 6f
				select kv.Key).ToList())
			{
				value.Remove(item);
			}
			return value.Keys.Count((long k) => k != except);
		}

		private static void GiveBack(long peer, ItemData it)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if (it != null && it.m_stack > 0)
			{
				if (peer == ZNet.GetUID())
				{
					ItemNet.GiveLocalPlayer(it);
					return;
				}
				ZPackage val = new ZPackage();
				ItemNet.Write(val, it);
				ZRoutedRpc.instance.InvokeRoutedRPC(peer, "SoroQoL_MucGive", new object[1] { val });
			}
		}

		private static void OnView(Container c, long sender, bool open)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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)
			if (Acc.NView(c).IsOwner())
			{
				ZDOID uid = Acc.NView(c).GetZDO().m_uid;
				if (!_viewers.TryGetValue(uid, out var value))
				{
					value = (_viewers[uid] = new Dictionary<long, float>());
				}
				if (open)
				{
					value[sender] = Time.time;
				}
				else
				{
					value.Remove(sender);
				}
			}
		}

		private static void OnTake(Container c, long sender, int x, int y, int amount, string prefab)
		{
			Safe.Run("MUC.Take", delegate
			{
				if (Acc.NView(c).IsOwner())
				{
					Inventory inventory = c.GetInventory();
					ItemData itemAt = inventory.GetItemAt(x, y);
					if (itemAt != null && !((Object)(object)itemAt.m_dropPrefab == (Object)null) && !(((Object)itemAt.m_dropPrefab).name != prefab))
					{
						int num = Mathf.Clamp(amount, 1, itemAt.m_stack);
						ItemData val = itemAt.Clone();
						val.m_stack = num;
						if (inventory.RemoveItem(itemAt, num))
						{
							GiveBack(sender, val);
						}
					}
				}
			});
		}

		private static void OnPut(Container c, long sender, int x, int y, ZPackage pkg)
		{
			ItemData val = null;
			try
			{
				val = ItemNet.Read(pkg);
				if (val == null)
				{
					return;
				}
				if (!Acc.NView(c).IsOwner())
				{
					GiveBack(sender, val);
					return;
				}
				Inventory inventory = c.GetInventory();
				if (x >= 0 && y >= 0)
				{
					inventory.GetItemAt(x, y);
				}
				int num = val.m_stack;
				if (x >= 0 && y >= 0 && x < inventory.GetWidth())
				{
					inventory.GetHeight();
				}
				if (num > 0)
				{
					ItemData val2 = val.Clone();
					val2.m_stack = num;
					num = ItemNet.AddAsMuch(inventory, val2);
				}
				if (num > 0)
				{
					ItemData val3 = val.Clone();
					val3.m_stack = num;
					GiveBack(sender, val3);
				}
			}
			catch (Exception e)
			{
				Safe.Report("MUC.Put", e);
				if (val != null)
				{
					GiveBack(sender, val);
				}
			}
		}

		private static bool Viewing(InventoryGui g, out Container c)
		{
			c = Acc.CurrentContainer(g);
			if (On && (Object)(object)c != (Object)null && (Object)(object)Acc.NView(c) != (Object)null && Acc.NView(c).IsValid())
			{
				return !c.IsOwner();
			}
			return false;
		}

		private static void SendPut(Container c, Player pl, ItemData item, int amount, int x, int y)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			Inventory inventory = ((Humanoid)pl).GetInventory();
			amount = Mathf.Clamp(amount, 1, item.m_stack);
			if (((Humanoid)pl).IsItemEquiped(item))
			{
				((Humanoid)pl).UnequipItem(item, false);
			}
			ItemData val = item.Clone();
			val.m_stack = amount;
			if (inventory.RemoveItem(item, amount))
			{
				ZPackage val2 = new ZPackage();
				ItemNet.Write(val2, val);
				Acc.NView(c).InvokeRPC("SoroQoL_MucPut", new object[3] { x, y, val2 });
			}
		}
	}
	internal static class Pieces
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetSceneAwake
		{
			private static void Postfix()
			{
				Safe.Run("Pieces.ZNetScene", Ensure);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDBAwake
		{
			private static void Postfix()
			{
				Safe.Run("Pieces.ObjectDB", Ensure);
			}
		}

		public const string ProductionName = "soro_production_chest";

		public const string ReinforcedName = "soro_production_chest_reinforced";

		private const string ReinforcedBase = "piece_chest";

		public const string TransferName = "soro_transfer_chest";

		public const string TotemName = "soro_crafting_totem";

		private const string ChestBase = "piece_chest_wood";

		private static readonly string[] TotemBases = new string[3] { "piece_banner01", "wood_pole2", "guard_stone" };

		private const string Workbench = "piece_workbench";

		private static GameObject _holder;

		private static GameObject _production;

		private static GameObject _reinforced;

		private static GameObject _transfer;

		private static GameObject _totem;

		private static GameObject FindPrefab(string name)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)