Decompiled source of Producers v1.0.9

plugins/Producers.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using ItemManager;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using PieceManager;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: Guid("E74EB49A-461D-48EA-85BC-F462D60C98C4")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyProduct("Producers")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("Producers")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.9")]
[assembly: AssemblyCompany("Radamanto")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.9.0")]
[module: <20d487de-864e-47b0-a3a9-6d2b38a0fcbc>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<bda8a508-d048-433c-ad00-176f3d49fd79>Embedded]
	internal sealed class <bda8a508-d048-433c-ad00-176f3d49fd79>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	[<bda8a508-d048-433c-ad00-176f3d49fd79>Embedded]
	internal sealed class <af2b6342-0953-40ed-9adc-717feea0f4c4>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <af2b6342-0953-40ed-9adc-717feea0f4c4>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <af2b6342-0953-40ed-9adc-717feea0f4c4>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[<bda8a508-d048-433c-ad00-176f3d49fd79>Embedded]
	[CompilerGenerated]
	internal sealed class <afae7602-7653-46c8-90d0-a9a3f3023251>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <afae7602-7653-46c8-90d0-a9a3f3023251>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[<bda8a508-d048-433c-ad00-176f3d49fd79>Embedded]
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class <20d487de-864e-47b0-a3a9-6d2b38a0fcbc>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <20d487de-864e-47b0-a3a9-6d2b38a0fcbc>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Producers
{
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	internal sealed class RD_BeeHive : MonoBehaviour
	{
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Container), "GetHoverName")]
		private static class Container_GetHoverName_BeeHive
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				RD_BeeHive rD_BeeHive = default(RD_BeeHive);
				if (((Component)__instance).TryGetComponent<RD_BeeHive>(ref rD_BeeHive))
				{
					__result = rD_BeeHive._name;
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Container), "GetHoverText")]
		private static class Container_GetHoverText_BeeHive
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				RD_BeeHive rD_BeeHive = default(RD_BeeHive);
				if (!((Component)__instance).TryGetComponent<RD_BeeHive>(ref rD_BeeHive))
				{
					return;
				}
				string text = "<color=yellow>" + ProducersDisplayCache.GetLocalizedName("Honey") + "</color>: " + ConsumablePerBatch + "x " + GetValidConsumableDisplayNames();
				string text2 = Localization.instance.Localize(rD_BeeHive._name);
				string text3 = Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open");
				if (!PrivateArea.CheckAccess(((Component)rD_BeeHive).transform.position, 0f, false, false))
				{
					__result = Localization.instance.Localize(text2 + "\n" + text + "\n$piece_noaccess");
					return;
				}
				int honeyCount = rD_BeeHive.GetHoneyCount();
				Inventory val = (((Object)(object)rD_BeeHive._container != (Object)null) ? rD_BeeHive._container.GetInventory() : null);
				if (val == null)
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, honeyCount, MaxHoney, text3, Localization.instance.Localize("$ve_beehive_no_consumable"));
				}
				else if (rD_BeeHive.IsFullForProduction(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, honeyCount, MaxHoney, text3, Localization.instance.Localize("$ve_beehive_full"));
				}
				else if (!HasEnoughConsumableForBatch(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, honeyCount, MaxHoney, text3, Localization.instance.Localize("$ve_beehive_no_consumable"));
				}
				else
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=orange>{5}</color>", text2, text, honeyCount, MaxHoney, text3, Localization.instance.Localize("$ve_beehive_working"));
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class ZNetScene_Awake_AddBeeHive
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				GameObject prefab = __instance.GetPrefab("RDP_beehive");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Piece component = prefab.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_waterPiece = false;
						component.m_noInWater = false;
						component.m_groundPiece = true;
					}
					if (!Object.op_Implicit((Object)(object)prefab.GetComponent<RD_BeeHive>()))
					{
						prefab.AddComponent<RD_BeeHive>();
					}
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class ObjectDB_Awake_CacheHoney
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ObjectDB __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					GameObject itemPrefab = __instance.GetItemPrefab("Honey");
					if (!Object.op_Implicit((Object)(object)itemPrefab))
					{
						_honeyItemPrefab = null;
					}
					else
					{
						_honeyItemPrefab = itemPrefab.GetComponent<ItemDrop>();
					}
				}
			}
		}

		private const string BeeHivePrefabName = "RDP_beehive";

		private const string HoneyPrefabName = "Honey";

		private const string TokenWorking = "$ve_beehive_working";

		private const string TokenNoConsumable = "$ve_beehive_no_consumable";

		private const string TokenFull = "$ve_beehive_full";

		private static readonly int ZdoStartTimeHash = StringExtensionMethods.GetStableHashCode("ve_beehive_starttime");

		private static readonly int ZdoAccTimeHash = StringExtensionMethods.GetStableHashCode("ve_beehive_acctime");

		private ZNetView _nview = null;

		private Piece _piece = null;

		private Container _container = null;

		private string _name = "$piece_container";

		private bool _productionTickRunning;

		private static string _cachedConsumablesRaw = string.Empty;

		private static HashSet<string> _cachedConsumablePrefabNames = new HashSet<string>(StringComparer.Ordinal);

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static ItemDrop _honeyItemPrefab;

		private static float SecPerBatch => Mathf.Max(0.1f, ProducersPlugin.CE_BeeHive_SecPerBatch.Value);

		private static int ConsumablePerBatch => Mathf.Max(1, ProducersPlugin.CE_BeeHive_ConsumablePerBatch.Value);

		private static int HoneyPerBatch => Mathf.Max(1, ProducersPlugin.CE_BeeHive_HoneyPerBatch.Value);

		private static int MaxHoney => Mathf.Max(1, ProducersPlugin.CE_BeeHive_MaxHoney.Value);

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
			_container = ((Component)this).GetComponent<Container>();
			if ((Object)(object)_piece != (Object)null && !string.IsNullOrEmpty(_piece.m_name))
			{
				_name = _piece.m_name;
			}
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_container == (Object)null))
			{
				Inventory inventory = _container.GetInventory();
				if (inventory != null)
				{
					InitializePlacementData();
					((MonoBehaviour)this).InvokeRepeating("UpdateOwnershipTick", 1f, 1f);
				}
			}
		}

		private void UpdateOwnershipTick()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				if (_productionTickRunning)
				{
					((MonoBehaviour)this).CancelInvoke("UpdateBeeHivePersistent");
					_productionTickRunning = false;
				}
			}
			else if (_nview.IsOwner())
			{
				if (!_productionTickRunning)
				{
					((MonoBehaviour)this).InvokeRepeating("UpdateBeeHivePersistent", 1f, 1f);
					_productionTickRunning = true;
				}
			}
			else if (_productionTickRunning)
			{
				((MonoBehaviour)this).CancelInvoke("UpdateBeeHivePersistent");
				_productionTickRunning = false;
			}
		}

		private void ResetProductionClock()
		{
			Producers_PersistentTimer.ResetProductionClock(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private double GetDeltaTime()
		{
			return Producers_PersistentTimer.GetDeltaTime(_nview, ZdoStartTimeHash);
		}

		private float GetAccumulator()
		{
			return Producers_PersistentTimer.GetAccumulator(_nview, ZdoAccTimeHash);
		}

		private void SetAccumulator(float t)
		{
			Producers_PersistentTimer.SetAccumulator(_nview, ZdoAccTimeHash, t);
		}

		private void InitializePlacementData()
		{
			if ((Object)(object)_piece != (Object)null)
			{
				_piece.m_waterPiece = false;
				_piece.m_noInWater = false;
				_piece.m_groundPiece = true;
			}
			Producers_PersistentTimer.InitializePersistentTimer(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private static HashSet<string> GetValidConsumablePrefabNames()
		{
			string text = ProducersPlugin.CE_BeeHive_ConsumablePrefab?.Value ?? string.Empty;
			if (string.Equals(_cachedConsumablesRaw, text, StringComparison.Ordinal))
			{
				return _cachedConsumablePrefabNames;
			}
			_cachedConsumablesRaw = text;
			_cachedConsumablePrefabNames = ParseConsumablePrefabNames(text);
			return _cachedConsumablePrefabNames;
		}

		private static HashSet<string> ParseConsumablePrefabNames(string raw)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (!string.IsNullOrWhiteSpace(raw))
			{
				string[] array = raw.Split(new char[1] { ',' });
				foreach (string text in array)
				{
					string text2 = text.Trim();
					if (!string.IsNullOrWhiteSpace(text2))
					{
						hashSet.Add(text2);
						if (hashSet.Count >= 10)
						{
							break;
						}
					}
				}
			}
			if (hashSet.Count == 0)
			{
				hashSet.Add("Dandelion");
			}
			return hashSet;
		}

		private static bool IsValidConsumablePrefab(string prefabName)
		{
			return !string.IsNullOrWhiteSpace(prefabName) && GetValidConsumablePrefabNames().Contains(prefabName);
		}

		private static string GetValidConsumableDisplayNames()
		{
			string text = ProducersPlugin.CE_BeeHive_ConsumablePrefab?.Value ?? string.Empty;
			return ProducersDisplayCache.GetConfiguredItemNames("beehive:" + text, GetValidConsumablePrefabNames());
		}

		private bool TryConsumeConsumable(Inventory inventory, int amountNeeded)
		{
			if (amountNeeded <= 0)
			{
				return true;
			}
			int num = amountNeeded;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (!((Object)(object)item.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)item.m_dropPrefab).name))
				{
					int num2 = Math.Min(item.m_stack, num);
					if (num2 > 0 && inventory.RemoveItem(item, num2))
					{
						num -= num2;
					}
					if (num <= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool HasEnoughConsumableForBatch(Inventory inventory)
		{
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)allItem.m_dropPrefab).name))
				{
					num += allItem.m_stack;
					if (num >= ConsumablePerBatch)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static int GetConsumableCount(Inventory inventory)
		{
			long num = 0L;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)allItem.m_dropPrefab).name))
				{
					num += allItem.m_stack;
					if (num >= int.MaxValue)
					{
						return int.MaxValue;
					}
				}
			}
			return (int)num;
		}

		private void UpdateBeeHivePersistent()
		{
			if (!_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			Inventory inventory = _container.GetInventory();
			if (inventory == null)
			{
				return;
			}
			if (!CanProduceOneBatchNow(inventory))
			{
				ResetProductionClock();
				return;
			}
			double deltaTime = GetDeltaTime();
			float num = GetAccumulator() + (float)deltaTime;
			int num2 = ((num / SecPerBatch >= 2.1474836E+09f) ? int.MaxValue : Mathf.FloorToInt(num / SecPerBatch));
			int num3 = GetConsumableCount(inventory) / ConsumablePerBatch;
			int num4 = Mathf.Max(0, MaxHoney - GetHoneyCount()) / HoneyPerBatch;
			int num5 = Mathf.Min(num2, Mathf.Min(num3, num4));
			if (num5 <= 0)
			{
				SetAccumulator(num);
				return;
			}
			int num6 = 0;
			for (int i = 0; i < num5; i++)
			{
				if (!CanProduceOneBatchNow(inventory))
				{
					break;
				}
				if (!TryConsumeConsumable(inventory, ConsumablePerBatch))
				{
					break;
				}
				if (!TryAddHoney(inventory, HoneyPerBatch))
				{
					break;
				}
				num6++;
			}
			if (num6 <= 0)
			{
				ResetProductionClock();
				return;
			}
			num -= (float)num6 * SecPerBatch;
			if (num < 0f)
			{
				num = 0f;
			}
			if (!CanProduceOneBatchNow(inventory))
			{
				ResetProductionClock();
			}
			else
			{
				SetAccumulator(num);
			}
		}

		private bool TryAddHoney(Inventory inventory, int amount)
		{
			if ((Object)(object)_honeyItemPrefab == (Object)null)
			{
				return false;
			}
			ItemData val = _honeyItemPrefab.m_itemData.Clone();
			val.m_dropPrefab = ((Component)_honeyItemPrefab).gameObject;
			val.m_stack = amount;
			val.m_quality = 1;
			return inventory.AddItem(val);
		}

		private static bool CanStackHoney(Inventory inventory)
		{
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab == (Object)null || ((Object)allItem.m_dropPrefab).name != "Honey" || allItem.m_stack >= allItem.m_shared.m_maxStackSize)
				{
					continue;
				}
				return true;
			}
			return false;
		}

		private bool CanProduceOneBatchNow(Inventory inventory)
		{
			if (!HasEnoughConsumableForBatch(inventory))
			{
				return false;
			}
			int honeyCount = GetHoneyCount();
			int num = Mathf.Max(0, MaxHoney - honeyCount);
			if (num < HoneyPerBatch)
			{
				return false;
			}
			if (!inventory.HaveEmptySlot() && !CanStackHoney(inventory))
			{
				return false;
			}
			if ((Object)(object)_honeyItemPrefab == (Object)null)
			{
				return false;
			}
			return true;
		}

		private bool IsFullForProduction(Inventory inventory)
		{
			int honeyCount = GetHoneyCount();
			int num = Mathf.Max(0, MaxHoney - honeyCount);
			if (num < HoneyPerBatch)
			{
				return true;
			}
			if (!inventory.HaveEmptySlot() && !CanStackHoney(inventory))
			{
				return true;
			}
			return false;
		}

		private int GetHoneyCount()
		{
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if (val == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && !(((Object)allItem.m_dropPrefab).name != "Honey"))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}
	}
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	internal sealed class RD_BirdHouse : MonoBehaviour
	{
		[HarmonyPatch(typeof(Container), "GetHoverName")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Container_GetHoverName_BirdHouse
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				RD_BirdHouse rD_BirdHouse = default(RD_BirdHouse);
				if (((Component)__instance).TryGetComponent<RD_BirdHouse>(ref rD_BirdHouse))
				{
					__result = rD_BirdHouse._name;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Container_GetHoverText_BirdHouse
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				RD_BirdHouse rD_BirdHouse = default(RD_BirdHouse);
				if (!((Component)__instance).TryGetComponent<RD_BirdHouse>(ref rD_BirdHouse))
				{
					return;
				}
				string text = "<color=yellow>" + ProducersDisplayCache.GetLocalizedName("Feathers") + "</color>: " + ConsumablePerBatch + "x " + GetValidConsumableDisplayNames();
				string text2 = Localization.instance.Localize(rD_BirdHouse._name);
				string text3 = Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open");
				if (!PrivateArea.CheckAccess(((Component)rD_BirdHouse).transform.position, 0f, false, false))
				{
					__result = Localization.instance.Localize(text2 + "\n" + text + "\n$piece_noaccess");
					return;
				}
				int featherCount = rD_BirdHouse.GetFeatherCount();
				Inventory val = (((Object)(object)rD_BirdHouse._container != (Object)null) ? rD_BirdHouse._container.GetInventory() : null);
				if (val == null)
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, featherCount, MaxFeathers, text3, Localization.instance.Localize("$ve_birdhouse_no_consumable"));
				}
				else if (rD_BirdHouse.IsFullForProduction(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, featherCount, MaxFeathers, text3, Localization.instance.Localize("$ve_birdhouse_full"));
				}
				else if (!HasEnoughConsumableForBatch(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text2, text, featherCount, MaxFeathers, text3, Localization.instance.Localize("$ve_birdhouse_no_consumable"));
				}
				else
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=orange>{5}</color>", text2, text, featherCount, MaxFeathers, text3, Localization.instance.Localize("$ve_birdhouse_working"));
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class ZNetScene_Awake_AddBirdHouse
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				GameObject prefab = __instance.GetPrefab("RDP_birdhouse");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Piece component = prefab.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_waterPiece = false;
						component.m_noInWater = false;
						component.m_groundPiece = false;
					}
					if (!Object.op_Implicit((Object)(object)prefab.GetComponent<RD_BirdHouse>()))
					{
						prefab.AddComponent<RD_BirdHouse>();
					}
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_CacheFeathers
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ObjectDB __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					GameObject itemPrefab = __instance.GetItemPrefab("Feathers");
					if (!Object.op_Implicit((Object)(object)itemPrefab))
					{
						_featherItemPrefab = null;
					}
					else
					{
						_featherItemPrefab = itemPrefab.GetComponent<ItemDrop>();
					}
				}
			}
		}

		private const string BirdHousePrefabName = "RDP_birdhouse";

		private const string FeatherPrefabName = "Feathers";

		private const string TokenWorking = "$ve_birdhouse_working";

		private const string TokenNoConsumable = "$ve_birdhouse_no_consumable";

		private const string TokenFull = "$ve_birdhouse_full";

		private static readonly int ZdoStartTimeHash = StringExtensionMethods.GetStableHashCode("ve_birdhouse_starttime");

		private static readonly int ZdoAccTimeHash = StringExtensionMethods.GetStableHashCode("ve_birdhouse_acctime");

		private ZNetView _nview = null;

		private Piece _piece = null;

		private Container _container = null;

		private string _name = "$piece_container";

		private bool _productionTickRunning;

		private static string _cachedConsumablesRaw = string.Empty;

		private static HashSet<string> _cachedConsumablePrefabNames = new HashSet<string>(StringComparer.Ordinal);

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static ItemDrop _featherItemPrefab;

		private static float SecPerBatch => Mathf.Max(0.1f, ProducersPlugin.CE_BirdHouse_SecPerBatch.Value);

		private static int ConsumablePerBatch => Mathf.Max(1, ProducersPlugin.CE_BirdHouse_ConsumablePerBatch.Value);

		private static int FeathersPerBatch => Mathf.Max(1, ProducersPlugin.CE_BirdHouse_FeathersPerBatch.Value);

		private static int MaxFeathers => Mathf.Max(1, ProducersPlugin.CE_BirdHouse_MaxFeathers.Value);

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
			_container = ((Component)this).GetComponent<Container>();
			if ((Object)(object)_piece != (Object)null && !string.IsNullOrEmpty(_piece.m_name))
			{
				_name = _piece.m_name;
			}
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_container == (Object)null))
			{
				Inventory inventory = _container.GetInventory();
				if (inventory != null)
				{
					InitializePlacementData();
					((MonoBehaviour)this).InvokeRepeating("UpdateOwnershipTick", 1f, 1f);
				}
			}
		}

		private void UpdateOwnershipTick()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				if (_productionTickRunning)
				{
					((MonoBehaviour)this).CancelInvoke("UpdateBirdHousePersistent");
					_productionTickRunning = false;
				}
			}
			else if (_nview.IsOwner())
			{
				if (!_productionTickRunning)
				{
					((MonoBehaviour)this).InvokeRepeating("UpdateBirdHousePersistent", 1f, 1f);
					_productionTickRunning = true;
				}
			}
			else if (_productionTickRunning)
			{
				((MonoBehaviour)this).CancelInvoke("UpdateBirdHousePersistent");
				_productionTickRunning = false;
			}
		}

		private void ResetProductionClock()
		{
			Producers_PersistentTimer.ResetProductionClock(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private double GetDeltaTime()
		{
			return Producers_PersistentTimer.GetDeltaTime(_nview, ZdoStartTimeHash);
		}

		private float GetAccumulator()
		{
			return Producers_PersistentTimer.GetAccumulator(_nview, ZdoAccTimeHash);
		}

		private void SetAccumulator(float t)
		{
			Producers_PersistentTimer.SetAccumulator(_nview, ZdoAccTimeHash, t);
		}

		private void InitializePlacementData()
		{
			if ((Object)(object)_piece != (Object)null)
			{
				_piece.m_waterPiece = false;
				_piece.m_noInWater = false;
				_piece.m_groundPiece = false;
			}
			Producers_PersistentTimer.InitializePersistentTimer(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private static HashSet<string> GetValidConsumablePrefabNames()
		{
			string text = ProducersPlugin.CE_BirdHouse_ConsumablePrefabs?.Value ?? string.Empty;
			if (string.Equals(_cachedConsumablesRaw, text, StringComparison.Ordinal))
			{
				return _cachedConsumablePrefabNames;
			}
			_cachedConsumablesRaw = text;
			_cachedConsumablePrefabNames = ParseConsumablePrefabNames(text);
			return _cachedConsumablePrefabNames;
		}

		private static HashSet<string> ParseConsumablePrefabNames(string raw)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (string.IsNullOrWhiteSpace(raw))
			{
				hashSet.Add("TurnipSeeds");
				return hashSet;
			}
			string[] array = raw.Split(new char[1] { ',' });
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim();
				if (!string.IsNullOrWhiteSpace(text2))
				{
					hashSet.Add(text2);
					if (hashSet.Count >= 10)
					{
						break;
					}
				}
			}
			if (hashSet.Count == 0)
			{
				hashSet.Add("TurnipSeeds");
			}
			return hashSet;
		}

		private static bool IsValidConsumablePrefab(string prefabName)
		{
			if (string.IsNullOrWhiteSpace(prefabName))
			{
				return false;
			}
			return GetValidConsumablePrefabNames().Contains(prefabName);
		}

		private static string GetValidConsumableDisplayNames()
		{
			string text = ProducersPlugin.CE_BirdHouse_ConsumablePrefabs?.Value ?? string.Empty;
			return ProducersDisplayCache.GetConfiguredItemNames("birdhouse:" + text, GetValidConsumablePrefabNames());
		}

		private static bool HasEnoughConsumableDistributed(Inventory inventory, int amountNeeded)
		{
			if (amountNeeded <= 0)
			{
				return true;
			}
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)allItem.m_dropPrefab).name))
				{
					num += allItem.m_stack;
					if (num >= amountNeeded)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryConsumeConsumableDistributed(Inventory inventory, int amountNeeded)
		{
			if (amountNeeded <= 0)
			{
				return true;
			}
			int num = amountNeeded;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (!((Object)(object)item.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)item.m_dropPrefab).name))
				{
					int num2 = Math.Min(item.m_stack, num);
					if (num2 > 0 && inventory.RemoveItem(item, num2))
					{
						num -= num2;
					}
					if (num <= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool HasEnoughConsumableForBatch(Inventory inventory)
		{
			return HasEnoughConsumableDistributed(inventory, ConsumablePerBatch);
		}

		private static int GetConsumableCount(Inventory inventory)
		{
			long num = 0L;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && IsValidConsumablePrefab(((Object)allItem.m_dropPrefab).name))
				{
					num += allItem.m_stack;
					if (num >= int.MaxValue)
					{
						return int.MaxValue;
					}
				}
			}
			return (int)num;
		}

		private void UpdateBirdHousePersistent()
		{
			if (!_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			Inventory inventory = _container.GetInventory();
			if (inventory == null)
			{
				return;
			}
			if (!CanProduceOneBatchNow(inventory))
			{
				ResetProductionClock();
				return;
			}
			double deltaTime = GetDeltaTime();
			float num = GetAccumulator() + (float)deltaTime;
			int num2 = ((num / SecPerBatch >= 2.1474836E+09f) ? int.MaxValue : Mathf.FloorToInt(num / SecPerBatch));
			int num3 = GetConsumableCount(inventory) / ConsumablePerBatch;
			int num4 = Mathf.Max(0, MaxFeathers - GetFeatherCount()) / FeathersPerBatch;
			int num5 = Mathf.Min(num2, Mathf.Min(num3, num4));
			if (num5 <= 0)
			{
				SetAccumulator(num);
				return;
			}
			int num6 = 0;
			for (int i = 0; i < num5; i++)
			{
				if (!CanProduceOneBatchNow(inventory))
				{
					break;
				}
				if (!TryConsumeConsumableDistributed(inventory, ConsumablePerBatch))
				{
					break;
				}
				if (!TryAddFeathers(inventory, FeathersPerBatch))
				{
					break;
				}
				num6++;
			}
			if (num6 <= 0)
			{
				ResetProductionClock();
				return;
			}
			num -= (float)num6 * SecPerBatch;
			if (num < 0f)
			{
				num = 0f;
			}
			if (!CanProduceOneBatchNow(inventory))
			{
				ResetProductionClock();
			}
			else
			{
				SetAccumulator(num);
			}
		}

		private bool TryAddFeathers(Inventory inventory, int amount)
		{
			if ((Object)(object)_featherItemPrefab == (Object)null)
			{
				return false;
			}
			ItemData val = _featherItemPrefab.m_itemData.Clone();
			val.m_dropPrefab = ((Component)_featherItemPrefab).gameObject;
			val.m_stack = amount;
			val.m_quality = 1;
			return inventory.AddItem(val);
		}

		private static bool CanStackFeathers(Inventory inventory)
		{
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab == (Object)null || ((Object)allItem.m_dropPrefab).name != "Feathers" || allItem.m_stack >= allItem.m_shared.m_maxStackSize)
				{
					continue;
				}
				return true;
			}
			return false;
		}

		private bool CanProduceOneBatchNow(Inventory inventory)
		{
			if (!HasEnoughConsumableForBatch(inventory))
			{
				return false;
			}
			int featherCount = GetFeatherCount();
			int num = Mathf.Max(0, MaxFeathers - featherCount);
			if (num < FeathersPerBatch)
			{
				return false;
			}
			if (!inventory.HaveEmptySlot() && !CanStackFeathers(inventory))
			{
				return false;
			}
			if ((Object)(object)_featherItemPrefab == (Object)null)
			{
				return false;
			}
			return true;
		}

		private bool IsFullForProduction(Inventory inventory)
		{
			int featherCount = GetFeatherCount();
			int num = Mathf.Max(0, MaxFeathers - featherCount);
			if (num < FeathersPerBatch)
			{
				return true;
			}
			if (!inventory.HaveEmptySlot() && !CanStackFeathers(inventory))
			{
				return true;
			}
			return false;
		}

		private int GetFeatherCount()
		{
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if (val == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && !(((Object)allItem.m_dropPrefab).name != "Feathers"))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}
	}
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	internal sealed class RD_CompostBin : MonoBehaviour
	{
		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
		internal sealed class BaitDefinition
		{
			public readonly string ConfigLabel;

			public readonly string[] PrefabCandidates;

			public readonly string[] Keywords;

			public readonly string DefaultConsumable;

			public int Amount;

			[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
			public ItemDrop ItemPrefab;

			public BaitDefinition(string configLabel, string[] prefabCandidates, string[] keywords, string defaultConsumable, int defaultAmount)
			{
				ConfigLabel = configLabel;
				PrefabCandidates = prefabCandidates;
				Keywords = keywords;
				DefaultConsumable = defaultConsumable;
				Amount = defaultAmount;
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverName")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Container_GetHoverName_CompostBin
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				RD_CompostBin componentInParent = ((Component)__instance).GetComponentInParent<RD_CompostBin>();
				if (!((Object)(object)componentInParent == (Object)null))
				{
					__result = componentInParent._name;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Container_GetHoverText_CompostBin
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				RD_CompostBin componentInParent = ((Component)__instance).GetComponentInParent<RD_CompostBin>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					return;
				}
				string acceptedLines = GetAcceptedLines();
				string text = Localization.instance.Localize(componentInParent._name);
				string text2 = Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open");
				if (!PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, false, false))
				{
					__result = Localization.instance.Localize(text + "\n" + acceptedLines + "\n$piece_noaccess");
					return;
				}
				int baitCount = componentInParent.GetBaitCount();
				Inventory val = (((Object)(object)componentInParent._container != (Object)null) ? componentInParent._container.GetInventory() : null);
				int baitIndex;
				if (val == null)
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, acceptedLines, baitCount, MaxBait, text2, Localization.instance.Localize("$ve_compostbin_no_consumable"));
				}
				else if (componentInParent.IsFullForProduction(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, acceptedLines, baitCount, MaxBait, text2, Localization.instance.Localize("$ve_compostbin_full"));
				}
				else if (!TryFindProducibleBait(val, out baitIndex))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, acceptedLines, baitCount, MaxBait, text2, Localization.instance.Localize("$ve_compostbin_no_consumable"));
				}
				else if (!componentInParent.CanProduceOneCycleNow(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, acceptedLines, baitCount, MaxBait, text2, Localization.instance.Localize("$ve_compostbin_full"));
				}
				else
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=orange>{5}</color>", text, acceptedLines, baitCount, MaxBait, text2, Localization.instance.Localize("$ve_compostbin_working"));
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class ZNetScene_Awake_AddCompostBin
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				GameObject prefab = __instance.GetPrefab("RDP_compost_bin");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Piece component = prefab.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_waterPiece = false;
						component.m_noInWater = false;
						component.m_groundPiece = false;
					}
					if (!Object.op_Implicit((Object)(object)prefab.GetComponent<RD_CompostBin>()))
					{
						prefab.AddComponent<RD_CompostBin>();
					}
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_ResetBaits
		{
			private static void Postfix()
			{
				_resolvedDb = null;
				BaitPrefabNames.Clear();
			}
		}

		internal static readonly BaitDefinition[] Baits = new BaitDefinition[9]
		{
			new BaitDefinition("Fishing Bait", new string[1] { "FishingBait" }, Array.Empty<string>(), "RawMeat", 10),
			new BaitDefinition("Mossy Fishing Bait", new string[2] { "FishingBaitForest", "BaitForest" }, new string[2] { "forest", "mossy" }, "DeerMeat", 10),
			new BaitDefinition("Sticky Fishing Bait", new string[2] { "FishingBaitSwamp", "BaitSwamp" }, new string[2] { "swamp", "sticky" }, "Entrails", 10),
			new BaitDefinition("Cold Fishing Bait", new string[4] { "FishingBaitCave", "FishingBaitMountain", "BaitCave", "BaitMountain" }, new string[3] { "cave", "mountain", "cold" }, "WolfMeat", 10),
			new BaitDefinition("Stingy Fishing Bait", new string[2] { "FishingBaitPlains", "BaitPlains" }, new string[2] { "plain", "stingy" }, "LoxMeat", 10),
			new BaitDefinition("Heavy Fishing Bait", new string[2] { "FishingBaitOcean", "BaitOcean" }, new string[2] { "ocean", "heavy" }, "SerpentMeat", 10),
			new BaitDefinition("Misty Fishing Bait", new string[2] { "FishingBaitMistlands", "BaitMistlands" }, new string[1] { "mist" }, "HareMeat", 10),
			new BaitDefinition("Hot Fishing Bait", new string[2] { "FishingBaitAshlands", "BaitAshlands" }, new string[2] { "ash", "hot" }, "AsksvinMeat", 10),
			new BaitDefinition("Frosty Fishing Bait", new string[2] { "FishingBaitDeepNorth", "BaitDeepNorth" }, new string[2] { "north", "frost" }, "SealBlubber", 10)
		};

		private static string[] _cachedRaws = Array.Empty<string>();

		private static Dictionary<string, int> _foodToBait = new Dictionary<string, int>(StringComparer.Ordinal);

		private static readonly HashSet<string> BaitPrefabNames = new HashSet<string>(StringComparer.Ordinal);

		private static readonly int[] ScratchCounts = new int[Baits.Length];

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static ObjectDB _resolvedDb;

		private const string CompostBinPrefabName = "RDP_compost_bin";

		private const string TokenWorking = "$ve_compostbin_working";

		private const string TokenNoConsumable = "$ve_compostbin_no_consumable";

		private const string TokenFull = "$ve_compostbin_full";

		private static readonly int ZdoStartTimeHash = StringExtensionMethods.GetStableHashCode("ve_compostbin_starttime");

		private static readonly int ZdoAccTimeHash = StringExtensionMethods.GetStableHashCode("ve_compostbin_acctime");

		private ZNetView _nview = null;

		private Piece _piece = null;

		private Container _container = null;

		private string _name = "$piece_container";

		private bool _productionTickRunning;

		private static float SecPerCycle => Mathf.Max(0.1f, ProducersPlugin.CE_CompostBin_SecPerCycle.Value);

		private static int ConsumablePerCycle => Mathf.Max(1, ProducersPlugin.CE_CompostBin_ConsumablePerCycle.Value);

		private static int MaxBait => Mathf.Max(1, ProducersPlugin.CE_CompostBin_MaxBait.Value);

		private static string[] ReadRaws()
		{
			string[] array = new string[Baits.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = ((ProducersPlugin.CE_CompostBin_Consumables.Length > i && ProducersPlugin.CE_CompostBin_Consumables[i] != null) ? (ProducersPlugin.CE_CompostBin_Consumables[i].Value ?? string.Empty) : string.Empty);
				ref string reference = ref array[i];
				reference = reference + "#" + ConsumablePerCycle;
			}
			return array;
		}

		private static void EnsureBaitsResolved()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_resolvedDb || instance.m_items == null || instance.m_items.Count == 0)
			{
				return;
			}
			_resolvedDb = instance;
			BaitPrefabNames.Clear();
			List<ItemDrop> list = new List<ItemDrop>();
			foreach (GameObject item in instance.m_items)
			{
				if (!((Object)(object)item == (Object)null) && ((Object)item).name.IndexOf("bait", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					ItemDrop component = item.GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null && !list.Contains(component))
					{
						list.Add(component);
					}
				}
			}
			Fish val = default(Fish);
			foreach (GameObject item2 in instance.m_items)
			{
				if ((Object)(object)item2 == (Object)null || !item2.TryGetComponent<Fish>(ref val))
				{
					continue;
				}
				foreach (BaitSetting bait in val.m_baits)
				{
					if (!((Object)(object)bait.m_bait == (Object)null) && !list.Contains(bait.m_bait))
					{
						list.Add(bait.m_bait);
					}
				}
			}
			HashSet<ItemDrop> hashSet = new HashSet<ItemDrop>();
			BaitDefinition[] baits = Baits;
			foreach (BaitDefinition baitDefinition in baits)
			{
				baitDefinition.ItemPrefab = null;
				string[] prefabCandidates = baitDefinition.PrefabCandidates;
				foreach (string b in prefabCandidates)
				{
					foreach (ItemDrop item3 in list)
					{
						if (hashSet.Contains(item3) || !string.Equals(((Object)item3).name, b, StringComparison.OrdinalIgnoreCase))
						{
							continue;
						}
						baitDefinition.ItemPrefab = item3;
						break;
					}
					if ((Object)(object)baitDefinition.ItemPrefab != (Object)null)
					{
						break;
					}
				}
				if ((Object)(object)baitDefinition.ItemPrefab == (Object)null)
				{
					string[] keywords = baitDefinition.Keywords;
					foreach (string value in keywords)
					{
						foreach (ItemDrop item4 in list)
						{
							if (hashSet.Contains(item4) || ((Object)item4).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) < 0)
							{
								continue;
							}
							baitDefinition.ItemPrefab = item4;
							break;
						}
						if ((Object)(object)baitDefinition.ItemPrefab != (Object)null)
						{
							break;
						}
					}
				}
				if (!((Object)(object)baitDefinition.ItemPrefab != (Object)null))
				{
					continue;
				}
				hashSet.Add(baitDefinition.ItemPrefab);
				BaitPrefabNames.Add(((Object)baitDefinition.ItemPrefab).name);
				if (instance.m_recipes == null)
				{
					continue;
				}
				foreach (Recipe recipe in instance.m_recipes)
				{
					if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || ((Object)recipe.m_item).name != ((Object)baitDefinition.ItemPrefab).name)
					{
						continue;
					}
					if (recipe.m_amount > 0)
					{
						baitDefinition.Amount = recipe.m_amount;
					}
					break;
				}
			}
		}

		private static void RefreshFoodMapIfNeeded()
		{
			EnsureBaitsResolved();
			string[] array = ReadRaws();
			bool flag = _cachedRaws.Length == array.Length;
			if (flag)
			{
				for (int i = 0; i < array.Length; i++)
				{
					if (!string.Equals(_cachedRaws[i], array[i], StringComparison.Ordinal))
					{
						flag = false;
						break;
					}
				}
			}
			if (flag)
			{
				return;
			}
			_cachedRaws = array;
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int j = 0; j < array.Length; j++)
			{
				if (!string.IsNullOrWhiteSpace(array[j]))
				{
					string text = array[j].Split(new char[1] { '#' })[0].Split(new char[1] { ',' })[0].Trim();
					if (!string.IsNullOrWhiteSpace(text) && !dictionary.ContainsKey(text))
					{
						dictionary[text] = j;
					}
				}
			}
			_foodToBait = dictionary;
		}

		private static bool TryGetBaitIndex(ItemData item, out int baitIndex)
		{
			baitIndex = -1;
			if ((Object)(object)item.m_dropPrefab == (Object)null)
			{
				return false;
			}
			return _foodToBait.TryGetValue(((Object)item.m_dropPrefab).name, out baitIndex);
		}

		private static string GetAcceptedLines()
		{
			RefreshFoodMapIfNeeded();
			string cacheKey = "compostbin:lines:" + string.Join("|", _cachedRaws) + ":" + (((Object)(object)_resolvedDb != (Object)null) ? "1" : "0");
			return ProducersDisplayCache.GetOrAdd(cacheKey, delegate
			{
				List<string> list = new List<string>();
				for (int i = 0; i < Baits.Length; i++)
				{
					string text = null;
					foreach (KeyValuePair<string, int> item in _foodToBait)
					{
						if (item.Value == i)
						{
							text = item.Key;
							break;
						}
					}
					if (text != null)
					{
						ItemDrop itemPrefab = Baits[i].ItemPrefab;
						string text2 = (((Object)(object)itemPrefab != (Object)null && !string.IsNullOrEmpty(itemPrefab.m_itemData.m_shared.m_name)) ? Localization.instance.Localize(itemPrefab.m_itemData.m_shared.m_name) : Baits[i].ConfigLabel);
						list.Add("<color=yellow>" + text2 + "</color>: " + ConsumablePerCycle + "x " + ProducersDisplayCache.GetLocalizedName(text));
					}
				}
				return (list.Count > 0) ? string.Join("\n", list) : "-";
			});
		}

		private static int AmountFor(int baitIndex)
		{
			return Mathf.Max(1, Baits[baitIndex].Amount);
		}

		private static int MinAmount()
		{
			int num = int.MaxValue;
			for (int i = 0; i < Baits.Length; i++)
			{
				num = Mathf.Min(num, AmountFor(i));
			}
			return num;
		}

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
			_container = ((Component)this).GetComponent<Container>();
			if ((Object)(object)_container == (Object)null)
			{
				_container = ((Component)this).GetComponentInChildren<Container>(true);
			}
			if ((Object)(object)_piece != (Object)null && !string.IsNullOrEmpty(_piece.m_name))
			{
				_name = _piece.m_name;
			}
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_container == (Object)null))
			{
				Inventory inventory = _container.GetInventory();
				if (inventory != null)
				{
					InitializePlacementData();
					((MonoBehaviour)this).InvokeRepeating("UpdateOwnershipTick", 1f, 1f);
				}
			}
		}

		private void UpdateOwnershipTick()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				if (_productionTickRunning)
				{
					((MonoBehaviour)this).CancelInvoke("UpdateCompostBinPersistent");
					_productionTickRunning = false;
				}
			}
			else if (_nview.IsOwner())
			{
				if (!_productionTickRunning)
				{
					((MonoBehaviour)this).InvokeRepeating("UpdateCompostBinPersistent", 1f, 1f);
					_productionTickRunning = true;
				}
			}
			else if (_productionTickRunning)
			{
				((MonoBehaviour)this).CancelInvoke("UpdateCompostBinPersistent");
				_productionTickRunning = false;
			}
		}

		private void ResetProductionClock()
		{
			Producers_PersistentTimer.ResetProductionClock(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private double GetDeltaTime()
		{
			return Producers_PersistentTimer.GetDeltaTime(_nview, ZdoStartTimeHash);
		}

		private float GetAccumulator()
		{
			return Producers_PersistentTimer.GetAccumulator(_nview, ZdoAccTimeHash);
		}

		private void SetAccumulator(float t)
		{
			Producers_PersistentTimer.SetAccumulator(_nview, ZdoAccTimeHash, t);
		}

		private void InitializePlacementData()
		{
			if ((Object)(object)_piece != (Object)null)
			{
				_piece.m_waterPiece = false;
				_piece.m_noInWater = false;
				_piece.m_groundPiece = false;
			}
			Producers_PersistentTimer.InitializePersistentTimer(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private static int CountAllConsumables(Inventory inventory)
		{
			long num = 0L;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (TryGetBaitIndex(allItem, out var _))
				{
					num += allItem.m_stack;
					if (num >= int.MaxValue)
					{
						return int.MaxValue;
					}
				}
			}
			return (int)num;
		}

		private static bool TryFindProducibleBait(Inventory inventory, out int baitIndex)
		{
			baitIndex = -1;
			RefreshFoodMapIfNeeded();
			int consumablePerCycle = ConsumablePerCycle;
			Array.Clear(ScratchCounts, 0, ScratchCounts.Length);
			List<ItemData> allItems = inventory.GetAllItems();
			foreach (ItemData item in allItems)
			{
				if (TryGetBaitIndex(item, out var baitIndex2) && baitIndex2 >= 0 && baitIndex2 < ScratchCounts.Length)
				{
					ScratchCounts[baitIndex2] += item.m_stack;
				}
			}
			foreach (ItemData item2 in allItems)
			{
				if (!TryGetBaitIndex(item2, out var baitIndex3) || baitIndex3 < 0 || baitIndex3 >= ScratchCounts.Length || ScratchCounts[baitIndex3] < consumablePerCycle || (Object)(object)Baits[baitIndex3].ItemPrefab == (Object)null)
				{
					continue;
				}
				baitIndex = baitIndex3;
				return true;
			}
			return false;
		}

		private static bool TryConsumeFoodForBait(Inventory inventory, int baitIndex, int amountNeeded)
		{
			int num = amountNeeded;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (TryGetBaitIndex(item, out var baitIndex2) && baitIndex2 == baitIndex)
				{
					int num2 = Math.Min(item.m_stack, num);
					if (num2 > 0 && inventory.RemoveItem(item, num2))
					{
						num -= num2;
					}
					if (num <= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryAddBait(Inventory inventory, int baitIndex, int amount)
		{
			ItemDrop itemPrefab = Baits[baitIndex].ItemPrefab;
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return false;
			}
			ItemData val = itemPrefab.m_itemData.Clone();
			val.m_dropPrefab = ((Component)itemPrefab).gameObject;
			val.m_stack = amount;
			val.m_quality = 1;
			return inventory.AddItem(val);
		}

		private static bool CanStackBait(Inventory inventory, int baitIndex)
		{
			ItemDrop itemPrefab = Baits[baitIndex].ItemPrefab;
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return false;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab == (Object)null || ((Object)allItem.m_dropPrefab).name != ((Object)itemPrefab).name || allItem.m_stack >= allItem.m_shared.m_maxStackSize)
				{
					continue;
				}
				return true;
			}
			return false;
		}

		private int GetBaitCount()
		{
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if (val == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && BaitPrefabNames.Contains(((Object)allItem.m_dropPrefab).name))
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private void UpdateCompostBinPersistent()
		{
			if (!_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			Inventory inventory = _container.GetInventory();
			if (inventory == null)
			{
				return;
			}
			if (!CanProduceOneCycleNow(inventory))
			{
				ResetProductionClock();
				return;
			}
			double deltaTime = GetDeltaTime();
			float num = GetAccumulator() + (float)deltaTime;
			int num2 = ((num / SecPerCycle >= 2.1474836E+09f) ? int.MaxValue : Mathf.FloorToInt(num / SecPerCycle));
			int num3 = CountAllConsumables(inventory) / ConsumablePerCycle;
			int num4 = Mathf.Max(0, MaxBait - GetBaitCount()) / MinAmount();
			int num5 = Mathf.Min(num2, Mathf.Min(num3, num4));
			if (num5 <= 0)
			{
				SetAccumulator(num);
				return;
			}
			int num6 = 0;
			for (int i = 0; i < num5; i++)
			{
				if (!CanProduceOneCycleNow(inventory))
				{
					break;
				}
				if (!TryFindProducibleBait(inventory, out var baitIndex))
				{
					break;
				}
				if (!TryConsumeFoodForBait(inventory, baitIndex, ConsumablePerCycle))
				{
					break;
				}
				if (!TryAddBait(inventory, baitIndex, AmountFor(baitIndex)))
				{
					break;
				}
				num6++;
			}
			if (num6 <= 0)
			{
				ResetProductionClock();
				return;
			}
			num -= (float)num6 * SecPerCycle;
			if (num < 0f)
			{
				num = 0f;
			}
			if (!CanProduceOneCycleNow(inventory))
			{
				ResetProductionClock();
			}
			else
			{
				SetAccumulator(num);
			}
		}

		private bool CanProduceOneCycleNow(Inventory inventory)
		{
			if (!TryFindProducibleBait(inventory, out var baitIndex))
			{
				return false;
			}
			int num = Mathf.Max(0, MaxBait - GetBaitCount());
			if (num < AmountFor(baitIndex))
			{
				return false;
			}
			if (!inventory.HaveEmptySlot() && !CanStackBait(inventory, baitIndex))
			{
				return false;
			}
			return true;
		}

		private bool IsFullForProduction(Inventory inventory)
		{
			int num = Mathf.Max(0, MaxBait - GetBaitCount());
			if (num < MinAmount())
			{
				return true;
			}
			if (!inventory.HaveEmptySlot())
			{
				for (int i = 0; i < Baits.Length; i++)
				{
					if (CanStackBait(inventory, i))
					{
						return false;
					}
				}
				return true;
			}
			return false;
		}
	}
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	public static class ValheimSfxMixerFix
	{
		private static bool _started;

		public static void Initialize(BaseUnityPlugin plugin)
		{
			if (!((Object)(object)plugin == (Object)null) && !Application.isBatchMode && !_started)
			{
				AssetBundle val = PrefabManager.RegisterAssetBundle("rd_producers");
				if (!((Object)(object)val == (Object)null))
				{
					_started = true;
					((MonoBehaviour)plugin).StartCoroutine(RouteWhenReady(val));
				}
			}
		}

		private static IEnumerator RouteWhenReady(AssetBundle bundle)
		{
			HashSet<AudioSource> sources = new HashSet<AudioSource>();
			HashSet<AudioMixer> bundledMixers = new HashSet<AudioMixer>();
			GameObject[] array = bundle.LoadAllAssets<GameObject>();
			foreach (GameObject prefab in array)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				AudioSource[] componentsInChildren = prefab.GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource source in componentsInChildren)
				{
					if (!((Object)(object)source == (Object)null))
					{
						sources.Add(source);
						AudioMixerGroup output = source.outputAudioMixerGroup;
						if ((Object)(object)output != (Object)null && (Object)(object)output.audioMixer != (Object)null)
						{
							bundledMixers.Add(output.audioMixer);
						}
					}
				}
			}
			while ((Object)(object)AudioMan.instance == (Object)null || (Object)(object)AudioMan.instance.m_masterMixer == (Object)null)
			{
				yield return null;
			}
			AudioMixer appliedMixer = null;
			WaitForSecondsRealtime retryDelay = new WaitForSecondsRealtime(1f);
			while (true)
			{
				AudioMan audioMan = AudioMan.instance;
				AudioMixer liveMixer = (((Object)(object)audioMan != (Object)null) ? audioMan.m_masterMixer : null);
				if ((Object)(object)liveMixer != (Object)null && (Object)(object)liveMixer != (Object)(object)appliedMixer)
				{
					AudioMixerGroup sfx = FindSfx(liveMixer);
					if ((Object)(object)sfx != (Object)null)
					{
						AudioSource[] array2 = Resources.FindObjectsOfTypeAll<AudioSource>();
						foreach (AudioSource source2 in array2)
						{
							if (!((Object)(object)source2 == (Object)null))
							{
								AudioMixerGroup output2 = source2.outputAudioMixerGroup;
								if ((Object)(object)output2 != (Object)null && (Object)(object)output2.audioMixer != (Object)(object)liveMixer && bundledMixers.Contains(output2.audioMixer))
								{
									sources.Add(source2);
								}
							}
						}
						foreach (AudioSource source3 in sources)
						{
							if ((Object)(object)source3 != (Object)null)
							{
								source3.outputAudioMixerGroup = sfx;
							}
						}
						appliedMixer = liveMixer;
					}
				}
				yield return retryDelay;
			}
		}

		[return: <af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static AudioMixerGroup FindSfx(AudioMixer mixer)
		{
			AudioMixerGroup[] array = mixer.FindMatchingGroups(string.Empty);
			foreach (AudioMixerGroup val in array)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, "SFX", StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}
	}
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	internal static class ProducersDisplayCache
	{
		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Localization_SetupLanguage_ClearCache
		{
			private static void Postfix()
			{
				Clear();
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Localization), "LoadCSV")]
		private static class Localization_LoadCSV_ClearCache
		{
			private static void Postfix()
			{
				Clear();
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_ClearCache
		{
			private static void Postfix()
			{
				Clear();
			}
		}

		private static readonly Dictionary<string, string> LocalizedNames = new Dictionary<string, string>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string> ConfiguredItemNames = new Dictionary<string, string>(StringComparer.Ordinal);

		internal static string GetLocalizedName(string prefabName)
		{
			if (LocalizedNames.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab(prefabName);
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			string text = ((ItemDrop)(obj?)).m_itemData?.m_shared?.m_name;
			string text2 = ((text != null && text.Length > 0) ? Localization.instance.Localize(text) : prefabName);
			LocalizedNames[prefabName] = text2;
			return text2;
		}

		internal static string GetConfiguredItemNames(string raw, IEnumerable<string> prefabs)
		{
			if (ConfiguredItemNames.TryGetValue(raw, out var value))
			{
				return value;
			}
			List<string> list = new List<string>();
			foreach (string prefab in prefabs)
			{
				list.Add(GetLocalizedName(prefab));
			}
			string text = ((list.Count > 0) ? string.Join(", ", list) : "-");
			ConfiguredItemNames[raw] = text;
			return text;
		}

		internal static string GetOrAdd(string cacheKey, Func<string> build)
		{
			if (ConfiguredItemNames.TryGetValue(cacheKey, out var value))
			{
				return value;
			}
			string text = build();
			ConfiguredItemNames[cacheKey] = text;
			return text;
		}

		internal static void Clear()
		{
			LocalizedNames.Clear();
			ConfiguredItemNames.Clear();
		}
	}
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	internal static class Producers_PersistentTimer
	{
		internal static double GetDeltaTime(ZNetView nview, int startTimeHash)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner() || (Object)(object)ZNet.instance == (Object)null)
			{
				return 0.0;
			}
			DateTime time = ZNet.instance.GetTime();
			ZDO zDO = nview.GetZDO();
			long num = zDO.GetLong(startTimeHash, time.Ticks);
			DateTime minValue = DateTime.MinValue;
			DateTime dateTime;
			if (num >= minValue.Ticks)
			{
				minValue = DateTime.MaxValue;
				if (num <= minValue.Ticks)
				{
					dateTime = new DateTime(num);
					goto IL_008b;
				}
			}
			dateTime = time;
			goto IL_008b;
			IL_008b:
			DateTime dateTime2 = dateTime;
			double num2 = (time - dateTime2).TotalSeconds;
			if (num2 < 0.0)
			{
				num2 = 0.0;
			}
			zDO.Set(startTimeHash, time.Ticks);
			return num2;
		}

		internal static float GetAccumulator(ZNetView nview, int accumulatorHash)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return 0f;
			}
			float num = nview.GetZDO().GetFloat(accumulatorHash, 0f);
			return (float.IsNaN(num) || float.IsInfinity(num) || num < 0f) ? 0f : num;
		}

		internal static void SetAccumulator(ZNetView nview, int accumulatorHash, float value)
		{
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
			{
				nview.GetZDO().Set(accumulatorHash, (float.IsNaN(value) || float.IsInfinity(value) || value < 0f) ? 0f : value);
			}
		}

		internal static void ResetProductionClock(ZNetView nview, int startTimeHash, int accumulatorHash)
		{
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
			{
				SetAccumulator(nview, accumulatorHash, 0f);
				if (!((Object)(object)ZNet.instance == (Object)null))
				{
					nview.GetZDO().Set(startTimeHash, ZNet.instance.GetTime().Ticks);
				}
			}
		}

		internal static void InitializePersistentTimer(ZNetView nview, int startTimeHash, int accumulatorHash)
		{
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner())
			{
				return;
			}
			ZDO zDO = nview.GetZDO();
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				long num = zDO.GetLong(startTimeHash, 0L);
				if (num == 0)
				{
					zDO.Set(startTimeHash, ZNet.instance.GetTime().Ticks);
				}
			}
			float num2 = zDO.GetFloat(accumulatorHash, 0f);
			if (float.IsNaN(num2) || float.IsInfinity(num2) || num2 < 0f)
			{
				zDO.Set(accumulatorHash, 0f);
			}
		}
	}
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	internal sealed class RD_FishTrap : MonoBehaviour
	{
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class ObjectDB_Awake_BuildBaitConversions
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ObjectDB __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				BaitConversions.Clear();
				Fish val = default(Fish);
				foreach (ItemDrop allItem in __instance.GetAllItems((ItemType)21, ""))
				{
					if (!((Component)allItem).TryGetComponent<Fish>(ref val))
					{
						continue;
					}
					foreach (BaitSetting bait in val.m_baits)
					{
						if ((Object)(object)bait.m_bait == (Object)null)
						{
							continue;
						}
						string itemStableKey = GetItemStableKey(bait.m_bait);
						if (!string.IsNullOrEmpty(itemStableKey))
						{
							if (BaitConversions.TryGetValue(itemStableKey, out var value))
							{
								value.AddFish(allItem);
							}
							else
							{
								BaitConversions[itemStableKey] = new BaitData(allItem);
							}
						}
					}
				}
			}
		}

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
		private sealed class BaitData
		{
			private readonly List<ItemData> _fishes = new List<ItemData>();

			public BaitData(ItemDrop fish)
			{
				AddFish(fish);
			}

			public void AddFish(ItemDrop fish)
			{
				foreach (ItemData fish2 in _fishes)
				{
					if ((Object)(object)fish2.m_dropPrefab == (Object)(object)((Component)fish).gameObject)
					{
						return;
					}
				}
				ItemData val = fish.m_itemData.Clone();
				val.m_dropPrefab = ((Component)fish).gameObject;
				_fishes.Add(val);
			}

			public bool HasFish(string fishPrefabName)
			{
				foreach (ItemData fish in _fishes)
				{
					if ((Object)(object)fish.m_dropPrefab != (Object)null && ((Object)fish.m_dropPrefab).name == fishPrefabName)
					{
						return true;
					}
				}
				return false;
			}

			public bool SupportsBiome(Biome biome)
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				foreach (ItemData fish in _fishes)
				{
					string fishPrefabName = (((Object)(object)fish.m_dropPrefab != (Object)null) ? ((Object)fish.m_dropPrefab).name : string.Empty);
					if (IsFishConfiguredForBiome(fishPrefabName, biome))
					{
						return true;
					}
				}
				return false;
			}

			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(2)]
			public ItemData GetFish(Biome biome)
			{
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				List<ItemData> list = new List<ItemData>();
				foreach (ItemData fish in _fishes)
				{
					string fishPrefabName = (((Object)(object)fish.m_dropPrefab != (Object)null) ? ((Object)fish.m_dropPrefab).name : string.Empty);
					if (IsFishConfiguredForBiome(fishPrefabName, biome))
					{
						list.Add(fish);
					}
				}
				if (list.Count <= 0)
				{
					return null;
				}
				ItemData val = list[Random.Range(0, list.Count)].Clone();
				val.m_stack = 1;
				return val;
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Container), "GetHoverName")]
		private static class Container_GetHoverName_FishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				RD_FishTrap rD_FishTrap = default(RD_FishTrap);
				if (((Component)__instance).TryGetComponent<RD_FishTrap>(ref rD_FishTrap))
				{
					__result = rD_FishTrap._name;
				}
			}
		}

		[HarmonyPatch(typeof(Container), "GetHoverText")]
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private static class Container_GetHoverText_FishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Container __instance, ref string __result)
			{
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				RD_FishTrap rD_FishTrap = default(RD_FishTrap);
				if (!((Component)__instance).TryGetComponent<RD_FishTrap>(ref rD_FishTrap))
				{
					return;
				}
				string text = Localization.instance.Localize(rD_FishTrap._name);
				string text2 = Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open");
				int fishCount = rD_FishTrap.GetFishCount();
				Biome placedBiome = rD_FishTrap.GetPlacedBiome();
				string fishBaitLines = GetFishBaitLines(placedBiome);
				if (!PrivateArea.CheckAccess(((Component)rD_FishTrap).transform.position, 0f, false, false))
				{
					__result = Localization.instance.Localize(text + "\n" + fishBaitLines + "\n$piece_noaccess");
					return;
				}
				if (!IsValidWaterPlacement(((Component)rD_FishTrap).transform.position))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, fishBaitLines, fishCount, MaxFish, text2, Localization.instance.Localize("$ve_fishtrap_invalid_water"));
					return;
				}
				if (!rD_FishTrap.HasConfiguredFishForPlacedBiome())
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, fishBaitLines, fishCount, MaxFish, text2, Localization.instance.Localize("$ve_fishtrap_wrong_biome"));
					return;
				}
				Inventory val = (((Object)(object)rD_FishTrap._container != (Object)null) ? rD_FishTrap._container.GetInventory() : null);
				if (val != null && rD_FishTrap.IsFullForProduction(val))
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, fishBaitLines, fishCount, MaxFish, text2, Localization.instance.Localize("$ve_fishtrap_full"));
				}
				else if (!rD_FishTrap.HasValidBaitForPlacedBiome())
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=red>{5}</color>", text, fishBaitLines, fishCount, MaxFish, text2, Localization.instance.Localize("$ve_fishtrap_no_bait"));
				}
				else
				{
					__result = string.Format("{0}\n{1}\n({2}/{3})\n{4}\n<color=orange>{5}</color>", text, fishBaitLines, fishCount, MaxFish, text2, Localization.instance.Localize("$ve_fishtrap_working"));
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(WearNTear), "IsWet")]
		private static class WearNTear_IsWet_FishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(WearNTear __instance, ref bool __result)
			{
				if (Object.op_Implicit((Object)(object)__instance) && !(Utils.GetPrefabName(((Component)__instance).gameObject) != "RDP_fishtrap"))
				{
					__result = false;
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static class Player_UpdatePlacementGhost_FishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(Player __instance)
			{
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				GameObject placementGhost = __instance.m_placementGhost;
				if (!Object.op_Implicit((Object)(object)placementGhost))
				{
					return;
				}
				Piece component = placementGhost.GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null) && !(Utils.GetPrefabName(((Component)component).gameObject) != "RDP_fishtrap"))
				{
					if (component.m_waterPiece)
					{
						component.m_waterPiece = false;
					}
					component.m_noInWater = false;
					component.m_groundPiece = true;
					if (!IsValidWaterPlacement(placementGhost.transform.position))
					{
						__instance.m_placementStatus = (PlacementStatus)1;
						component.SetInvalidPlacementHeightlight(true);
					}
				}
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class Player_TryPlacePiece_FishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static bool Prefix(Player __instance, Piece piece, ref bool __result)
			{
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)piece == (Object)null)
				{
					return true;
				}
				if (Utils.GetPrefabName(((Component)piece).gameObject) != "RDP_fishtrap")
				{
					return true;
				}
				GameObject placementGhost = __instance.m_placementGhost;
				Vector3 position = (Object.op_Implicit((Object)(object)placementGhost) ? placementGhost.transform.position : ((Component)piece).transform.position);
				if (IsValidWaterPlacement(position))
				{
					return true;
				}
				piece.SetInvalidPlacementHeightlight(true);
				((Character)__instance).Message((MessageType)2, Localization.instance.Localize("$ve_fishtrap_invalid_water"), 0, (Sprite)null, false);
				__result = false;
				return false;
			}
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetScene_Awake_AddFishTrap
		{
			[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				GameObject prefab = __instance.GetPrefab("RDP_fishtrap");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Piece component = prefab.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						component.m_waterPiece = false;
						component.m_noInWater = false;
						component.m_groundPiece = true;
					}
					if (!Object.op_Implicit((Object)(object)prefab.GetComponent<RD_FishTrap>()))
					{
						prefab.AddComponent<RD_FishTrap>();
					}
				}
			}
		}

		private static readonly Dictionary<string, BaitData> BaitConversions = new Dictionary<string, BaitData>(StringComparer.Ordinal);

		private static readonly Dictionary<Biome, HashSet<string>> VanillaFishByBiome = new Dictionary<Biome, HashSet<string>>
		{
			[(Biome)1] = new HashSet<string>(StringComparer.Ordinal) { "Fish1", "Fish2" },
			[(Biome)8] = new HashSet<string>(StringComparer.Ordinal) { "Fish1", "Fish2", "Fish5" },
			[(Biome)2] = new HashSet<string>(StringComparer.Ordinal) { "Fish2", "Fish6", "Fish4_cave" },
			[(Biome)4] = new HashSet<string>(StringComparer.Ordinal) { "Fish4_cave" },
			[(Biome)16] = new HashSet<string>(StringComparer.Ordinal) { "Fish7", "Fish8" },
			[(Biome)256] = new HashSet<string>(StringComparer.Ordinal) { "Fish3", "Fish8", "Fish12" },
			[(Biome)512] = new HashSet<string>(StringComparer.Ordinal) { "Fish9", "Fish12" },
			[(Biome)32] = new HashSet<string>(StringComparer.Ordinal) { "Fish11", "Fish12" },
			[(Biome)64] = new HashSet<string>(StringComparer.Ordinal) { "Fish10", "Fish12" }
		};

		private const string TrapPrefabName = "RDP_fishtrap";

		private const string TokenInvalidWater = "$ve_fishtrap_invalid_water";

		private const string TokenWorking = "$ve_fishtrap_working";

		private const string TokenWrongBiome = "$ve_fishtrap_wrong_biome";

		private const string TokenNoBait = "$ve_fishtrap_no_bait";

		private const string TokenFull = "$ve_fishtrap_full";

		private static readonly int ZdoPlacedBiomeHash = StringExtensionMethods.GetStableHashCode("ve_fishtrap_biome");

		private static readonly int ZdoStartTimeHash = StringExtensionMethods.GetStableHashCode("ve_fishtrap_starttime");

		private static readonly int ZdoAccTimeHash = StringExtensionMethods.GetStableHashCode("ve_fishtrap_acctime");

		private ZNetView _nview = null;

		private Piece _piece = null;

		private Container _container = null;

		private string _name = "$piece_container";

		private bool _productionTickRunning;

		private const float MinWaterDepth = 0.5f;

		private const float MaxWaterDepth = 1.5f;

		private static float SecPerUnit => Mathf.Max(0.1f, ProducersPlugin.CE_FishTrap_SecPerUnit.Value);

		private static int MaxFish => Mathf.Max(1, ProducersPlugin.CE_FishTrap_MaxFish.Value);

		private static float ChanceToIncreaseQuality => Mathf.Clamp01(ProducersPlugin.CE_FishTrap_ChanceToIncreaseQuality.Value);

		private static string GetItemStableKey(ItemData item)
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null && !string.IsNullOrEmpty(((Object)item.m_dropPrefab).name))
			{
				return ((Object)item.m_dropPrefab).name;
			}
			return string.Empty;
		}

		private static string GetItemStableKey(ItemDrop item)
		{
			if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(((Object)item).name))
			{
				return ((Object)item).name;
			}
			return string.Empty;
		}

		private static bool IsFishConfiguredForBiome(string fishPrefabName, Biome biome)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(fishPrefabName))
			{
				return false;
			}
			HashSet<string> value;
			return VanillaFishByBiome.TryGetValue(biome, out value) && value.Contains(fishPrefabName);
		}

		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(2)]
		private bool TryGetBaitConversion([<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(1)] List<ItemData> items, Biome placedBiome, out ItemData bait, out BaitData data)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			bait = null;
			data = null;
			foreach (ItemData item in items)
			{
				string itemStableKey = GetItemStableKey(item);
				if (string.IsNullOrEmpty(itemStableKey) || !BaitConversions.TryGetValue(itemStableKey, out var value) || !value.SupportsBiome(placedBiome))
				{
					continue;
				}
				bait = item;
				data = value;
				return true;
			}
			return false;
		}

		private bool HasValidBaitForPlacedBiome()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if (val == null)
			{
				return false;
			}
			ItemData bait;
			BaitData data;
			return TryGetBaitConversion(val.GetAllItems(), GetPlacedBiome(), out bait, out data);
		}

		private static int GetBaitCount(Inventory inventory, Biome biome)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			long num = 0L;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				string itemStableKey = GetItemStableKey(allItem);
				if (!string.IsNullOrEmpty(itemStableKey) && BaitConversions.TryGetValue(itemStableKey, out var value) && value.SupportsBiome(biome))
				{
					num += allItem.m_stack;
					if (num >= int.MaxValue)
					{
						return int.MaxValue;
					}
				}
			}
			return (int)num;
		}

		private bool HasConfiguredFishForPlacedBiome()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Biome placedBiome = GetPlacedBiome();
			foreach (KeyValuePair<string, BaitData> baitConversion in BaitConversions)
			{
				if (baitConversion.Value.SupportsBiome(placedBiome))
				{
					return true;
				}
			}
			return false;
		}

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
			_container = ((Component)this).GetComponent<Container>();
			if ((Object)(object)_piece != (Object)null && !string.IsNullOrEmpty(_piece.m_name))
			{
				_name = _piece.m_name;
			}
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_container == (Object)null))
			{
				Inventory inventory = _container.GetInventory();
				if (inventory != null)
				{
					InitializePlacementData();
					((MonoBehaviour)this).InvokeRepeating("UpdateOwnershipTick", 1f, 1f);
				}
			}
		}

		private void UpdateOwnershipTick()
		{
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				if (_productionTickRunning)
				{
					((MonoBehaviour)this).CancelInvoke("UpdateTrapPersistent");
					_productionTickRunning = false;
				}
			}
			else if (_nview.IsOwner())
			{
				if (!_productionTickRunning)
				{
					((MonoBehaviour)this).InvokeRepeating("UpdateTrapPersistent", 1f, 1f);
					_productionTickRunning = true;
				}
			}
			else if (_productionTickRunning)
			{
				((MonoBehaviour)this).CancelInvoke("UpdateTrapPersistent");
				_productionTickRunning = false;
			}
		}

		private double GetDeltaTime()
		{
			return Producers_PersistentTimer.GetDeltaTime(_nview, ZdoStartTimeHash);
		}

		private float GetAccumulator()
		{
			return Producers_PersistentTimer.GetAccumulator(_nview, ZdoAccTimeHash);
		}

		private void SetAccumulator(float t)
		{
			Producers_PersistentTimer.SetAccumulator(_nview, ZdoAccTimeHash, t);
		}

		private void ResetProductionClock()
		{
			Producers_PersistentTimer.ResetProductionClock(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private void InitializePlacementData()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected I4, but got Unknown
			if ((Object)(object)_piece != (Object)null)
			{
				_piece.m_waterPiece = false;
				_piece.m_noInWater = false;
				_piece.m_groundPiece = true;
			}
			if (_nview.IsOwner())
			{
				ZDO zDO = _nview.GetZDO();
				if (zDO.GetInt(ZdoPlacedBiomeHash, 0) == 0)
				{
					Biome val = Heightmap.FindBiome(((Component)this).transform.position);
					zDO.Set(ZdoPlacedBiomeHash, (int)val, false);
				}
			}
			Producers_PersistentTimer.InitializePersistentTimer(_nview, ZdoStartTimeHash, ZdoAccTimeHash);
		}

		private static string GetDisplayName(string prefabName)
		{
			return ProducersDisplayCache.GetLocalizedName(prefabName);
		}

		private static string GetFishBaitLines(Biome biome)
		{
			//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)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return ProducersDisplayCache.GetOrAdd($"fishtrap:lines:{biome}", delegate
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				if (!VanillaFishByBiome.TryGetValue(biome, out var value) || value.Count == 0)
				{
					return "-";
				}
				List<string> list = new List<string>();
				foreach (string item in value)
				{
					List<string> list2 = new List<string>();
					foreach (KeyValuePair<string, BaitData> baitConversion in BaitConversions)
					{
						if (baitConversion.Value.HasFish(item))
						{
							list2.Add(GetDisplayName(baitConversion.Key));
						}
					}
					list.Add("<color=yellow>" + GetDisplayName(item) + "</color>: " + ((list2.Count > 0) ? string.Join(", ", list2) : "-"));
				}
				return string.Join("\n", list);
			});
		}

		private static bool IsValidWaterPlacement(Vector3 position)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			float waterLevel = ZoneSystem.instance.m_waterLevel;
			float num = waterLevel - position.y;
			if (num < 0.5f)
			{
				return false;
			}
			if (num > 1.5f)
			{
				return false;
			}
			return true;
		}

		private Biome GetPlacedBiome()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected I4, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return Heightmap.FindBiome(((Component)this).transform.position);
			}
			return (Biome)_nview.GetZDO().GetInt(ZdoPlacedBiomeHash, (int)Heightmap.FindBiome(((Component)this).transform.position));
		}

		private void UpdateTrapPersistent()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!_nview.IsValid() || !_nview.IsOwner())
			{
				return;
			}
			Inventory inventory = _container.GetInventory();
			if (inventory == null)
			{
				return;
			}
			if (!CanProduceOneUnitNow(inventory))
			{
				ResetProductionClock();
				return;
			}
			double deltaTime = GetDeltaTime();
			float num = GetAccumulator() + (float)deltaTime;
			int num2 = ((num / SecPerUnit >= 2.1474836E+09f) ? int.MaxValue : Mathf.FloorToInt(num / SecPerUnit));
			int baitCount = GetBaitCount(inventory, GetPlacedBiome());
			int num3 = Mathf.Max(0, MaxFish - GetFishCount());
			int num4 = Mathf.Min(num2, Mathf.Min(baitCount, num3));
			if (num4 <= 0)
			{
				SetAccumulator(num);
				return;
			}
			int num5 = 0;
			for (int i = 0; i < num4; i++)
			{
				if (!CanProduceOneUnitNow(inventory))
				{
					break;
				}
				if (!TryProduceOneFish())
				{
					break;
				}
				num5++;
			}
			if (num5 <= 0)
			{
				ResetProductionClock();
				return;
			}
			num -= (float)num5 * SecPerUnit;
			if (num < 0f)
			{
				num = 0f;
			}
			if (!CanProduceOneUnitNow(inventory))
			{
				ResetProductionClock();
			}
			else
			{
				SetAccumulator(num);
			}
		}

		private bool TryProduceOneFish()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = _container.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			Biome placedBiome = GetPlacedBiome();
			if (!TryGetBaitConversion(inventory.GetAllItems(), placedBiome, out var bait, out var data))
			{
				return false;
			}
			if (bait == null || data == null)
			{
				return false;
			}
			ItemData fish = data.GetFish(placedBiome);
			if (fish == null)
			{
				return false;
			}
			fish.m_quality = RollQuality(fish);
			if (!inventory.AddItem(fish))
			{
				return false;
			}
			inventory.RemoveOneItem(bait);
			return true;
		}

		private static int RollQuality(ItemData item)
		{
			int num = Mathf.Max(1, item.m_shared.m_maxQuality);
			int result = 1;
			for (int i = 1; i < num; i++)
			{
				if (!(Random.value <= ChanceToIncreaseQuality))
				{
					break;
				}
				result = i + 1;
			}
			return result;
		}

		private bool CanProduceOneUnitNow(Inventory inventory)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!IsValidWaterPlacement(((Component)this).transform.position))
			{
				return false;
			}
			if (!HasConfiguredFishForPlacedBiome())
			{
				return false;
			}
			if (!HasValidBaitForPlacedBiome())
			{
				return false;
			}
			int fishCount = GetFishCount();
			int num = Mathf.Max(0, MaxFish - fishCount);
			if (num <= 0)
			{
				return false;
			}
			if (!inventory.HaveEmptySlot())
			{
				return false;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			Biome placedBiome = GetPlacedBiome();
			if (!TryGetBaitConversion(inventory.GetAllItems(), placedBiome, out var bait, out var data))
			{
				return false;
			}
			if (bait == null || data == null)
			{
				return false;
			}
			return true;
		}

		private bool IsFullForProduction(Inventory inventory)
		{
			int fishCount = GetFishCount();
			int num = Mathf.Max(0, MaxFish - fishCount);
			if (num <= 0)
			{
				return true;
			}
			if (!inventory.HaveEmptySlot())
			{
				return true;
			}
			return false;
		}

		private int GetFishCount()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if (val == null)
			{
				return 0;
			}
			List<ItemData> allItems = val.GetAllItems();
			int num = 0;
			foreach (ItemData item in allItems)
			{
				if ((int)item.m_shared.m_itemType == 21)
				{
					num += item.m_stack;
				}
			}
			return num;
		}
	}
	[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(1)]
	[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(0)]
	[BepInPlugin("radamanto.Producers", "Producers", "1.0.9")]
	public class ProducersPlugin : BaseUnityPlugin
	{
		[<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			public bool? Browsable = false;
		}

		internal static ConfigEntry<float> CE_BeeHive_SecPerBatch = null;

		internal static ConfigEntry<int> CE_BeeHive_ConsumablePerBatch = null;

		internal static ConfigEntry<string> CE_BeeHive_ConsumablePrefab = null;

		internal static ConfigEntry<int> CE_BeeHive_HoneyPerBatch = null;

		internal static ConfigEntry<int> CE_BeeHive_MaxHoney = null;

		internal static ConfigEntry<float> CE_BirdHouse_SecPerBatch = null;

		internal static ConfigEntry<int> CE_BirdHouse_ConsumablePerBatch = null;

		internal static ConfigEntry<int> CE_BirdHouse_FeathersPerBatch = null;

		internal static ConfigEntry<int> CE_BirdHouse_MaxFeathers = null;

		internal static ConfigEntry<string> CE_BirdHouse_ConsumablePrefabs = null;

		internal static ConfigEntry<float> CE_FishTrap_SecPerUnit = null;

		internal static ConfigEntry<int> CE_FishTrap_MaxFish = null;

		internal static ConfigEntry<float> CE_FishTrap_ChanceToIncreaseQuality = null;

		internal static ConfigEntry<float> CE_CompostBin_SecPerCycle = null;

		internal static ConfigEntry<int> CE_CompostBin_ConsumablePerCycle = null;

		internal static ConfigEntry<int> CE_CompostBin_MaxBait = null;

		internal static ConfigEntry<string>[] CE_CompostBin_Consumables = new ConfigEntry<string>[0];

		internal static ConfigEntry<bool> CE_BlockVanillaBeeHive = null;

		internal static ConfigEntry<bool> CE_BlockHaldorFishingRod = null;

		internal static ConfigEntry<bool> CE_BlockHaldorFishingBait = null;

		public const string ModGUID = "radamanto.Producers";

		public const string ModName = "Producers";

		public const string ModVersion = "1.0.9";

		private readonly Harmony _harmony = new Harmony("radamanto.Producers");

		private static bool _bootstrapped;

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static ConfigSync ConfigSync;

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private static ConfigEntry<bool> _serverConfigLocked;

		[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)]
		private FileSystemWatcher _configWatcher;

		private long _lastCfgWrite;

		private bool _reloadScheduled;

		private bool _watcherReady;

		private void Configure()
		{
			CE_BeeHive_SecPerBatch = Cfg("02 - BeeHive", "02.01 - SecondsPerCycle", 600f, "Seconds required to complete one production cycle.");
			CE_BeeHive_HoneyPerBatch = Cfg("02 - BeeHive", "02.02 - HoneyPerCycle", 1, "Honey produced per production cycle.");
			CE_BeeHive_ConsumablePerBatch = Cfg("02 - BeeHive", "02.03 - ConsumablePerCycle", 1, "Amount of the configured consumable prefab consumed per production cycle.");
			CE_BeeHive_MaxHoney = Cfg("02 - BeeHive", "02.04 - MaxHoney", 250, "Maximum honey stored inside the beehive container.");
			CE_BeeHive_ConsumablePrefab = Cfg("02 - BeeHive", "02.05 - ConsumablePrefab", "Dandelion", "Prefab names of valid consumable items for the beehive, separated by commas. Supports up to 10 items.");
			CE_BirdHouse_SecPerBatch = Cfg("03 - BirdHouse", "03.01 - SecondsPerCycle", 300f, "Seconds required to complete one production cycle.");
			CE_BirdHouse_FeathersPerBatch = Cfg("03 - BirdHouse", "03.02 - FeathersPerCycle", 5, "Feathers produced per production cycle.");
			CE_BirdHouse_ConsumablePerBatch = Cfg("03 - BirdHouse", "03.03 - ConsumablePerCycle", 1, "Amount of valid consumable items consumed per production cycle.");
			CE_BirdHouse_MaxFeathers = Cfg("03 - BirdHouse", "03.04 - MaxFeathers", 250, "Maximum feathers stored inside the birdhouse container.");
			CE_BirdHouse_ConsumablePrefabs = Cfg("03 - BirdHouse", "03.05 - ConsumablePrefabs", "TurnipSeeds,CarrotSeeds,OnionSeeds", "Prefab names of valid consumable items for the birdhouse, separated by commas. Supports up to 10 items.");
			CE_FishTrap_SecPerUnit = Cfg("04 - FishTrap", "04.01 - SecondsPerFish", 600f, "Seconds required to produce one fish.");
			CE_FishTrap_MaxFish = Cfg("04 - FishTrap", "04.02 - MaxFish", 100, "Maximum fish stored inside the trap container.");
			CE_FishTrap_ChanceToIncreaseQuality = Cfg("04 - FishTrap", "04.03 - ChanceToIncreaseQuality", 0.2f, "Chance to increase fish quality by one step per roll. Range: 0.0 to 1.0.");
			CE_CompostBin_SecPerCycle = Cfg("05 - CompostBin", "05.01 - SecondsPerCycle", 300f, "Seconds required to complete one production cycle.");
			CE_CompostBin_ConsumablePerCycle = Cfg("05 - CompostBin", "05.02 - ConsumablePerCycle", 1, "Amount of the consumable item consumed per production cycle.");
			CE_CompostBin_MaxBait = Cfg("05 - CompostBin", "05.03 - MaxBait", 250, "Maximum bait (all types combined) stored inside the compost bin container.");
			CE_CompostBin_Consumables = new ConfigEntry<string>[RD_CompostBin.Baits.Length];
			for (int i = 0; i < RD_CompostBin.Baits.Length; i++)
			{
				RD_CompostBin.BaitDefinition baitDefinition = RD_CompostBin.Baits[i];
				CE_CompostBin_Consumables[i] = Cfg("05 - CompostBin", $"05.{4 + i:00} - {baitDefinition.ConfigLabel} Consumable", baitDefinition.DefaultConsumable, "Prefab name of the consumable item that produces " + baitDefinition.ConfigLabel + ". Accepts 1 item.");
			}
			CE_BlockVanillaBeeHive = Cfg("06 - Vanilla BeeHive", "06.01 - BlockVanillaBeeHive", defaultValue: true, "Disables the vanilla beehive recipe and removes it from the hammer build menu.");
			CE_BlockHaldorFishingRod = Cfg("07 - FishingItems", "07.01 - BlockHaldorFishingRod", defaultValue: false, "Removes Fishing Rod from Haldor shop.");
			CE_BlockHaldorFishingBait = Cfg("07 - FishingItems", "07.02 - BlockHaldorFishingBait", defaultValue: false, "Removes Fishing Bait from Haldor shop.");
		}

		private void Awake()
		{
			Localizer.Load();
			if (!_bootstrapped)
			{
				bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
				try
				{
					SetupServerSync();
					Configure();
					Pieces_Registry.RegisterPieces();
					Effect_Registry.RegisterEffects();
					_harmony.PatchAll();
					ValheimSfxMixerFix.Initialize((BaseUnityPlugin)(object)this);
					_bootstrapped = true;
				}
				finally
				{
					((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
				}
				((BaseUnityPlugin)this).Config.Save();
				SetupConfigWatcher();
			}
		}

		private void OnDestroy()
		{
			_watcherReady = false;
			if (_configWatcher != null)
			{
				_configWatcher.EnableRaisingEvents = false;
				_configWatcher.Dispose();
				_configWatcher = null;
			}
			_reloadScheduled = false;
		}

		private void SetupServerSync()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			ConfigSync = new ConfigSync(((BaseUnityPlugin)this).Info.Metadata.GUID)
			{
				DisplayName = ((BaseUnityPlugin)this).Info.Metadata.Name,
				CurrentVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString(),
				MinimumRequiredVersion = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString()
			};
			_serverConfigLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "LockConfiguration", true, new ConfigDescription("If true, the server locks synchronized configs.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			ConfigSync.AddLockingConfigEntry<bool>(_serverConfigLocked);
		}

		private ConfigEntry<T> BindConfig<[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			if (ConfigSync == null)
			{
				throw new InvalidOperationException("ServerSync has not been initialized.");
			}
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> BindConfig<[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return BindConfig(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		private ConfigEntry<T> Cfg<[<af2b6342-0953-40ed-9adc-717feea0f4c4>Nullable(2)] T>(string section, string key, T defaultValue, string description, bool synced = true)
		{
			return BindConfig(section, key, defaultValue, description, synced);
		}

		private void SetupConfigWatcher()
		{
			try
			{
				_watcherReady = false;
				_configWatcher?.Dispose();
				_configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath))
				{
					IncludeSubdirectories = false,
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
					SynchronizingObject = ThreadingHelper.SynchronizingObject
				};
				_configWatcher.Changed += OnConfigFileChanged;
				_configWatcher.Created += OnConfigFileChanged;
				_configWatcher.Renamed += [<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)] (object _, RenamedEventArgs args) =>
				{
					OnConfigFileChanged(_, args);
				};
				_configWatcher.Error += [<afae7602-7653-46c8-90d0-a9a3f3023251>NullableContext(0)] (object _, ErrorEventArgs args) =>
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"Configuration watcher failed: {args.GetException()}");
				};
				_watcherReady = true;
				_configWatcher.EnableRaisingEvents = true;
			}
			catch (Exception arg)
			{
				_watcherReady = false;
				_configWatcher?.Dispose();
				_configWatcher = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"Automatic configuration reload is unavailable: {arg}");
			}
		}

		private void OnConfigFileChanged(object sender, FileSystemEventArgs args)
		{
			if (_watcherReady)
			{
				_lastCfgWrite = Stopwatch.GetTimestamp();
				if (!_reloadScheduled)
				{
					_reloadScheduled = true;
					((MonoBehaviour)this).StartCoroutine(ReloadConfigAfterQuietPeriod());
				}
			}
		}

		private IEnumerator ReloadConfigAfterQuietPeriod()
		{
			try
			{
				for (int attempt = 0; attempt < 3; attempt++)
				{
					if (!_watcherReady)
					{
						break;
					}
					while (_watcherReady && (double)(Stopwatch.GetTimestamp() - _lastCfgWrite) / (double)Stopwatch.Frequency < 0.75)
					{
						yield return null;
					}
					if (!_watcherReady || ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()))
					{
						break;
					}
					bool saveOnSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
					bool retry = false;
					try
					{
						((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
						((BaseUnityPlugin)this).Config.Reload();
						((BaseUnityPlugin)this).Logger.LogInfo((object)"Configuration reloaded.");
					}
					catch (IOException ex)
					{
						IOException error = ex;
						retry = true;
						if (attempt == 2)
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)$"Configuration could not be read after 3 attempts: {error}");
						}
					}
					catch (Exception ex2)
					{
						Exception error2 = ex2;
						((BaseUnityPlugin)this).Logger.LogError((object)$"Configuration reload failed: {error2}");
					}
					finally
					{
						((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnSet;
					}
					if (!retry)
					{
						break;
					}
					_lastCfgWrite = Stopwatch.GetTimestamp();
				}
			}
			finally
			{
				_reloadScheduled = false;
			}
		}
	}
	public static class Effect_Registry
	{
		public static void RegisterEffects()
		{
			PrefabManager.RegisterPrefab("rd_producers", "vfx_Place_beehive_rd_producers");
			PrefabManager.RegisterPrefab("rd_producers", "sfx_build_hammer_wood_rd_producers");
			PrefabManager.RegisterPrefab("rd_producers", "vfx_SawDust_rd_producers");
			PrefabManager.RegisterPrefab("rd_producers", "sfx_wood_destroyed_rd_producers");
		}
	}
	public static class Pieces_Registry
	{
		public static void RegisterPieces()
		{
			BuildPiece buildPiece = new BuildPiece("rd_producers", "RDP_beehive");
			buildPiece.Crafting.Set(PieceManager.CraftingTable.Workbench);
			buildPiece.Category.Set(BuildPieceCategory.Crafting);
			buildPiece.SpecialProperties.AdminOnly = false;
			buildPiece.RequiredItems.Add("QueenBee", 3, recover: true);
			buildPiece.RequiredItems.Add("Wood", 25, recover: true);
			MaterialRe