Decompiled source of FeedLikeGrandma v1.0.0

FeedLikeGrandma.dll

Decompiled 8 hours 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.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 BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.RepresentationModel;
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: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FeedLikeGrandma")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("FeedLikeGrandma")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LocalizationManager
{
	[PublicAPI]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		private static BaseUnityPlugin? _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		public static event Action? OnLocalizationComplete;

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out string value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out Dictionary<string, Func<string>> value2))
			{
				text = value2.Aggregate(text, (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, Func<T, string>? convertConfigValue = null) where T : notnull
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += delegate
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			_ = plugin;
		}

		public static void LoadLocalizationLater(Localization __instance)
		{
			LoadLocalization(Localization.instance, __instance.GetSelectedLanguage());
		}

		public static void SafeCallLocalizeComplete()
		{
			Localizer.OnLocalizationComplete?.Invoke();
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string[] array = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' });
				if (array.Length >= 2)
				{
					string text = array[1];
					if (dictionary.ContainsKey(text))
					{
						Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
					}
					else
					{
						dictionary[text] = item;
					}
				}
			}
			byte[] array2 = LoadTranslationFromAssembly("English");
			if (array2 == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml.");
			}
			Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array2));
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.TryGetValue(language, out var value))
				{
					text2 = File.ReadAllText(value);
				}
				else
				{
					byte[] array3 = LoadTranslationFromAssembly(language);
					if (array3 != null)
					{
						text2 = Encoding.UTF8.GetString(array3);
					}
				}
			}
			if (text2 == null && dictionary.TryGetValue("English", out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string>(2) { ".json", ".yml" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalizationLater", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "SafeCallLocalizeComplete", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static byte[]? LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
	public static class LocalizationManagerVersion
	{
		public const string Version = "1.4.1";
	}
}
namespace System.Runtime.CompilerServices
{
	internal static class IsExternalInit
	{
	}
}
namespace FeedLikeGrandma
{
	internal static class FeedConsoleCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__WriteReference;

			public static ConsoleOptionsFetcher <1>__GetEmptyOptions;
		}

		private static readonly List<string> EmptyOptions = new List<string>();

		private static bool Registered;

		internal static void Register()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			if (!Registered)
			{
				Registered = true;
				object obj = <>O.<0>__WriteReference;
				if (obj == null)
				{
					ConsoleEvent val = WriteReference;
					<>O.<0>__WriteReference = val;
					obj = (object)val;
				}
				object obj2 = <>O.<1>__GetEmptyOptions;
				if (obj2 == null)
				{
					ConsoleOptionsFetcher val2 = GetEmptyOptions;
					<>O.<1>__GetEmptyOptions = val2;
					obj2 = (object)val2;
				}
				new ConsoleCommand("flg:reference", "Write generated FeedLikeGrandma reference YAML. Usage: flg:reference", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)obj2, false, false, false);
			}
		}

		private static List<string> GetEmptyOptions()
		{
			return EmptyOptions;
		}

		private static void WriteReference(ConsoleEventArgs args)
		{
			if (FeedLikeGrandmaPlugin.TryWriteReferenceConfigurationFile(out string path, out string error))
			{
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("Wrote FeedLikeGrandma reference to " + path);
				}
			}
			else
			{
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString(error);
				}
			}
		}
	}
	internal static class FeedAutoFeedSystem
	{
		private const float ContainerCleanupInterval = 5f;

		private static readonly float[] DropPointAngles = new float[8] { 0f, 45f, -45f, 90f, -90f, 135f, -135f, 180f };

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

		private static float _nextContainerCleanupTime;

		internal static void Shutdown()
		{
			RegisteredFeedContainers.Clear();
			_nextContainerCleanupTime = 0f;
		}

		internal static void RegisterContainer(Container? container)
		{
			if (IsContainerAlive(container) && FeedBarrelSystem.IsFeedBarrel(container))
			{
				FeedBarrelSystem.ApplyConfiguredContainerSize(container);
				if (!RegisteredFeedContainers.Contains(container))
				{
					RegisteredFeedContainers.Add(container);
				}
			}
		}

		internal static void DeregisterContainer(Container? container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				RegisteredFeedContainers.Remove(container);
			}
		}

		internal static void RefreshRegisteredContainerSizes()
		{
			CleanupContainers();
			foreach (Container registeredFeedContainer in RegisteredFeedContainers)
			{
				FeedBarrelSystem.ApplyConfiguredContainerSize(registeredFeedContainer);
			}
		}

		internal static bool TryFindClosestConsumableFromFeedBarrel(MonsterAI monsterAI, float maxRange, out ItemDrop? consumable)
		{
			//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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			consumable = null;
			if (!FeedBarrelSystem.IsEnabled)
			{
				return false;
			}
			if ((Object)(object)monsterAI == (Object)null || maxRange <= 0f)
			{
				return false;
			}
			if (monsterAI.m_consumeItems == null || monsterAI.m_consumeItems.Count == 0)
			{
				return false;
			}
			CleanupContainersThrottled();
			if (RegisteredFeedContainers.Count == 0)
			{
				return false;
			}
			GameObject gameObject = ((Component)monsterAI).gameObject;
			if (!FeedSystem.HasRuleFor(gameObject))
			{
				return false;
			}
			ZNetView component = gameObject.GetComponent<ZNetView>();
			Tameable component2 = gameObject.GetComponent<Tameable>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || (Object)(object)component2 == (Object)null || !component2.IsHungry() || ((BaseAI)monsterAI).IsAlerted())
			{
				return false;
			}
			Vector3 position = ((Component)monsterAI).transform.position;
			float sqrRange = maxRange * maxRange;
			Container val = null;
			ItemData val2 = null;
			Vector3 dropPosition = Vector3.zero;
			float num = float.PositiveInfinity;
			foreach (Container registeredFeedContainer in RegisteredFeedContainers)
			{
				if (IsEligibleContainer(registeredFeedContainer, position, sqrRange))
				{
					Vector3 val3 = GetContainerCenter(registeredFeedContainer) - position;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (!(sqrMagnitude >= num) && TrySelectFood(monsterAI, registeredFeedContainer, out ItemData item) && item != null && TryGetReachableDropPoint(monsterAI, registeredFeedContainer, position, maxRange, out var dropPosition2))
					{
						val = registeredFeedContainer;
						val2 = item;
						dropPosition = dropPosition2;
						num = sqrMagnitude;
					}
				}
			}
			if ((Object)(object)val != (Object)null && val2 != null && TryRemoveAndDrop(val, val2, dropPosition, out consumable) && (Object)(object)consumable != (Object)null)
			{
				return true;
			}
			return false;
		}

		private static bool TrySelectFood(MonsterAI monsterAI, Container container, out ItemData? item)
		{
			item = null;
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			if (!FeedSystem.TrySelectAutoFeedItem(monsterAI, inventory.GetAllItems(), out item) || item == null)
			{
				return false;
			}
			return EnsureDropPrefab(item);
		}

		private static bool TryRemoveAndDrop(Container container, ItemData item, Vector3 dropPosition, out ItemDrop? droppedItem)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			droppedItem = null;
			Inventory inventory = container.GetInventory();
			ZNetView nview = container.m_nview;
			if (inventory == null || (Object)(object)nview == (Object)null || !nview.IsValid())
			{
				return false;
			}
			if (!nview.IsOwner())
			{
				nview.ClaimOwnership();
			}
			if (!nview.IsOwner())
			{
				return false;
			}
			ItemData val = item.Clone();
			val.m_dropPrefab = item.m_dropPrefab;
			if (!inventory.RemoveOneItem(item))
			{
				return false;
			}
			container.Save();
			droppedItem = ItemDrop.DropItem(val, 1, dropPosition, ((Component)container).transform.rotation);
			return (Object)(object)droppedItem != (Object)null;
		}

		private static bool TryGetReachableDropPoint(MonsterAI monsterAI, Container container, Vector3 animalPosition, float maxRange, out Vector3 dropPosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			Vector3 containerCenter = GetContainerCenter(container);
			Vector3 val = (((Object)(object)container.m_piece != (Object)null) ? ((StaticTarget)container.m_piece).FindClosestPoint(animalPosition) : containerCenter);
			Vector3 val2 = HorizontalNormalized(animalPosition - val);
			if (((Vector3)(ref val2)).sqrMagnitude <= 0f)
			{
				val2 = -((Component)container).transform.forward;
			}
			float num = Mathf.Max(1.25f, monsterAI.m_consumeRange * 0.75f);
			if (TryUseDropPoint(monsterAI, animalPosition, val + val2 * num, maxRange, out dropPosition))
			{
				return true;
			}
			float num2 = Mathf.Max(1.5f, monsterAI.m_consumeRange + 0.5f);
			float[] dropPointAngles = DropPointAngles;
			foreach (float num3 in dropPointAngles)
			{
				Vector3 val3 = Quaternion.Euler(0f, num3, 0f) * val2;
				if (TryUseDropPoint(monsterAI, animalPosition, containerCenter + val3 * num2, maxRange, out dropPosition))
				{
					return true;
				}
			}
			dropPosition = Vector3.zero;
			return false;
		}

		private static bool TryUseDropPoint(MonsterAI monsterAI, Vector3 animalPosition, Vector3 point, float maxRange, out Vector3 dropPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004a: Unknown result type (might be due to invalid IL or missing references)
			point = SnapToGround(point);
			Vector3 val = point - animalPosition;
			if (((Vector3)(ref val)).sqrMagnitude > maxRange * maxRange || !((BaseAI)monsterAI).HavePath(point))
			{
				dropPosition = Vector3.zero;
				return false;
			}
			dropPosition = point + Vector3.up * 0.25f;
			return true;
		}

		private static Vector3 GetContainerCenter(Container container)
		{
			//IL_0020: 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)
			if ((Object)(object)container.m_piece != (Object)null)
			{
				return ((StaticTarget)container.m_piece).GetCenter();
			}
			return ((Component)container).transform.position;
		}

		private static Vector3 HorizontalNormalized(Vector3 vector)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			vector.y = 0f;
			if (!(((Vector3)(ref vector)).sqrMagnitude > 0.0001f))
			{
				return Vector3.zero;
			}
			return ((Vector3)(ref vector)).normalized;
		}

		private static Vector3 SnapToGround(Vector3 point)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			float y = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(point, ref y))
			{
				point.y = y;
			}
			return point;
		}

		private static bool IsEligibleContainer(Container container, Vector3 animalPosition, float sqrRange)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!IsContainerObjectValid(container))
			{
				return false;
			}
			Inventory inventory = container.GetInventory();
			if (inventory == null || inventory.NrOfItems() <= 0 || container.IsInUse())
			{
				return false;
			}
			if (!FeedBarrelSystem.IsEnabled || !FeedBarrelSystem.IsFeedBarrel(container))
			{
				return false;
			}
			Vector3 val = GetContainerCenter(container) - animalPosition;
			return ((Vector3)(ref val)).sqrMagnitude <= sqrRange;
		}

		private static bool IsContainerAlive(Container? container)
		{
			return (Object)(object)container != (Object)null;
		}

		private static bool IsContainerObjectValid(Container? container)
		{
			if (!IsContainerAlive(container))
			{
				return false;
			}
			ZNetView nview = container.m_nview;
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || container.GetInventory() == null)
			{
				return false;
			}
			return nview.GetZDO().GetLong(ZDOVars.s_creator, 0L) != 0;
		}

		private static bool EnsureDropPrefab(ItemData item)
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return true;
			}
			GameObject dropPrefab = default(GameObject);
			if (ObjectDB.instance == null || !ObjectDB.instance.TryGetItemPrefab(item.m_shared, ref dropPrefab))
			{
				return false;
			}
			item.m_dropPrefab = dropPrefab;
			return true;
		}

		private static void CleanupContainersThrottled()
		{
			if (RegisteredFeedContainers.Count != 0 && !(Time.time < _nextContainerCleanupTime))
			{
				_nextContainerCleanupTime = Time.time + 5f;
				CleanupContainers();
			}
		}

		private static void CleanupContainers()
		{
			RegisteredFeedContainers.RemoveAll((Container container) => !IsContainerAlive(container) || !FeedBarrelSystem.IsFeedBarrel(container));
		}
	}
	internal static class FeedBarrelSystem
	{
		private sealed class RendererMaterialSnapshot
		{
			public Renderer Renderer { get; }

			public Material[] Materials { get; }

			public RendererMaterialSnapshot(Renderer renderer, Material[] materials)
			{
				Renderer = renderer;
				Materials = materials;
			}
		}

		internal const string PrefabName = "FLG_FeedBarrel";

		private const string SourcePrefabName = "piece_chest_barrel";

		private const string EctoplasmMaterialName = "ectoplasm_mat";

		private const int DefaultColumns = 6;

		private const int DefaultRows = 2;

		private const int MinColumns = 6;

		private const int MaxColumns = 8;

		private const int MinRows = 2;

		private const int MaxRows = 100;

		private const int IconSize = 128;

		private const int IconLayer = 30;

		private static GameObject? _prefab;

		private static GameObject? _prefabContainer;

		private static readonly Dictionary<string, Material> MaterialLookupCache = new Dictionary<string, Material>(StringComparer.OrdinalIgnoreCase);

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

		private static List<RendererMaterialSnapshot>? _originalMaterials;

		private static Sprite? _originalIcon;

		private static Sprite? _ectoplasmIcon;

		private static bool _materialLookupCacheBuilt;

		internal static bool IsEnabled => !string.IsNullOrWhiteSpace(FeedLikeGrandmaPlugin.FeedBarrelRecipe.Value);

		internal static void OnGameDataChanged()
		{
			MaterialLookupCache.Clear();
			MaterialLookupMissCache.Clear();
			_materialLookupCacheBuilt = false;
		}

		internal static void RegisterPrefabsAndPieces(ObjectDB? objectDb = null)
		{
			GameObject val = EnsurePrefab();
			if (val != null)
			{
				ConfigurePrefab(val, objectDb ?? ObjectDB.instance);
				if (ZNetScene.instance != null)
				{
					RegisterWithZNetScene(ZNetScene.instance, val);
				}
				RegisterWithHammer(objectDb ?? ObjectDB.instance, val);
				FeedAutoFeedSystem.RefreshRegisteredContainerSizes();
			}
		}

		internal static bool IsFeedBarrel(Container? container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			return IsFeedBarrel(((Component)container).gameObject);
		}

		internal static bool IsFeedBarrel(GameObject? gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return false;
			}
			return string.Equals(Utils.GetPrefabName(gameObject), "FLG_FeedBarrel", StringComparison.Ordinal);
		}

		private static GameObject? EnsurePrefab()
		{
			if (_prefab != null)
			{
				return _prefab;
			}
			GameObject val = FindScenePrefab("FLG_FeedBarrel");
			if (val != null)
			{
				_prefab = val;
				return _prefab;
			}
			GameObject val2 = FindScenePrefab("piece_chest_barrel");
			if (val2 == null)
			{
				return null;
			}
			GameObject val3 = Object.Instantiate<GameObject>(val2, EnsurePrefabContainer().transform);
			((Object)val3).name = "FLG_FeedBarrel";
			if (val3.GetComponent<Piece>() == null || val3.GetComponent<Container>() == null || val3.GetComponent<ZNetView>() == null)
			{
				FeedLikeGrandmaPlugin.Log.LogWarning((object)"Could not create FLG_FeedBarrel: piece_chest_barrel did not have the expected Piece, Container, and ZNetView components.");
				Object.Destroy((Object)(object)val3);
				return null;
			}
			_prefab = val3;
			return _prefab;
		}

		private static void ConfigurePrefab(GameObject prefab, ObjectDB? objectDb)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Piece component = prefab.GetComponent<Piece>();
			if (component != null)
			{
				bool isEnabled = IsEnabled;
				component.m_name = "$flg_feed_barrel";
				component.m_description = "$flg_feed_barrel_description";
				component.m_enabled = isEnabled;
				component.m_category = (PieceCategory)0;
				StoreOriginalIcon(component);
				StoreOriginalMaterials(prefab);
				ApplyConfiguredMaterial(prefab, component);
				if (objectDb != null)
				{
					component.m_resources = (isEnabled ? BuildRequirements(objectDb, FeedLikeGrandmaPlugin.FeedBarrelRecipe.Value).ToArray() : Array.Empty<Requirement>());
				}
			}
			Container component2 = prefab.GetComponent<Container>();
			if (component2 != null)
			{
				component2.m_name = "$flg_feed_barrel";
				ApplyConfiguredContainerSize(component2);
			}
		}

		internal static void ApplyConfiguredContainerSize(Container? container)
		{
			if (container != null && IsFeedBarrel(container))
			{
				GetConfiguredContainerSize(out var columns, out var rows);
				container.m_width = columns;
				container.m_height = rows;
				Inventory inventory = container.GetInventory();
				if (inventory != null)
				{
					inventory.m_width = columns;
					inventory.m_height = rows;
				}
			}
		}

		private static void ApplyConfiguredMaterial(GameObject prefab, Piece piece)
		{
			RestoreOriginalMaterials();
			piece.m_icon = _originalIcon;
			if (FeedLikeGrandmaPlugin.FeedBarrelMaterialStyle.Value != FeedLikeGrandmaPlugin.FeedBarrelMaterial.Ectoplasm)
			{
				return;
			}
			Material val = ResolveMaterial("ectoplasm_mat");
			if (val == null)
			{
				FeedLikeGrandmaPlugin.Log.LogWarning((object)"FLG_FeedBarrel material 'ectoplasm_mat' was not found. Using default barrel material.");
				return;
			}
			ApplyMaterialOverride(prefab, val);
			if (_ectoplasmIcon == null)
			{
				_ectoplasmIcon = RenderPieceIcon(prefab);
			}
			if (_ectoplasmIcon != null)
			{
				piece.m_icon = _ectoplasmIcon;
			}
		}

		private static void GetConfiguredContainerSize(out int columns, out int rows)
		{
			columns = ((FeedLikeGrandmaPlugin.FeedBarrelContainerColumns != null) ? FeedLikeGrandmaPlugin.FeedBarrelContainerColumns.Value : 6);
			rows = ((FeedLikeGrandmaPlugin.FeedBarrelContainerRows != null) ? FeedLikeGrandmaPlugin.FeedBarrelContainerRows.Value : 2);
			columns = Mathf.Clamp(columns, 6, 8);
			rows = Mathf.Clamp(rows, 2, 100);
		}

		private static void RegisterWithZNetScene(ZNetScene zNetScene, GameObject prefab)
		{
			int stableHashCode = StringExtensionMethods.GetStableHashCode("FLG_FeedBarrel");
			if ((Object)(object)prefab.GetComponent<ZNetView>() != (Object)null)
			{
				if (zNetScene.m_prefabs.All((GameObject existing) => (Object)(object)existing == (Object)null || ((Object)existing).name != "FLG_FeedBarrel"))
				{
					zNetScene.m_prefabs.Add(prefab);
				}
			}
			else if (zNetScene.m_nonNetViewPrefabs.All((GameObject existing) => (Object)(object)existing == (Object)null || ((Object)existing).name != "FLG_FeedBarrel"))
			{
				zNetScene.m_nonNetViewPrefabs.Add(prefab);
			}
			if (!zNetScene.m_namedPrefabs.ContainsKey(stableHashCode))
			{
				zNetScene.m_namedPrefabs.Add(stableHashCode, prefab);
			}
			else if ((Object)(object)zNetScene.m_namedPrefabs[stableHashCode] == (Object)null || ((Object)zNetScene.m_namedPrefabs[stableHashCode]).name == "FLG_FeedBarrel")
			{
				zNetScene.m_namedPrefabs[stableHashCode] = prefab;
			}
		}

		private static void RegisterWithHammer(ObjectDB? objectDb, GameObject prefab)
		{
			if (objectDb == null)
			{
				return;
			}
			GameObject itemPrefab = objectDb.GetItemPrefab("Hammer");
			PieceTable val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>())?.m_itemData.m_shared.m_buildPieces;
			if (val != null)
			{
				val.m_pieces.RemoveAll((GameObject existing) => (Object)(object)existing == (Object)null || ((Object)existing).name == "FLG_FeedBarrel");
				if (!IsEnabled)
				{
					RefreshLocalBuildTable(val);
					return;
				}
				val.m_pieces.Add(prefab);
				RefreshLocalBuildTable(val);
			}
		}

		private static void RefreshLocalBuildTable(PieceTable pieceTable)
		{
			if (Player.m_localPlayer != null && Player.m_localPlayer.m_buildPieces != null && (Object)(object)Player.m_localPlayer.m_buildPieces == (Object)(object)pieceTable)
			{
				((Humanoid)Player.m_localPlayer).SetPlaceMode(pieceTable);
			}
		}

		private static IEnumerable<Requirement> BuildRequirements(ObjectDB objectDb, string recipeText)
		{
			if (string.IsNullOrWhiteSpace(recipeText))
			{
				yield break;
			}
			string[] array = recipeText.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Trim().Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length != 0)
				{
					string text = array2[0].Trim();
					int result = 1;
					if (array2.Length > 1)
					{
						int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
						result = Mathf.Max(1, result);
					}
					GameObject val = FindItemPrefab(objectDb, text);
					ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>());
					if (val2 == null)
					{
						FeedLikeGrandmaPlugin.Log.LogWarning((object)("FLG_FeedBarrel build ingredient '" + text + "' was not found."));
						continue;
					}
					yield return new Requirement
					{
						m_resItem = val2,
						m_amount = result,
						m_amountPerLevel = 0,
						m_recover = true
					};
				}
			}
		}

		private static GameObject? FindItemPrefab(ObjectDB objectDb, string itemName)
		{
			GameObject itemPrefab = objectDb.GetItemPrefab(itemName);
			if (itemPrefab != null)
			{
				return itemPrefab;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(itemName);
			if (!objectDb.m_itemByHash.TryGetValue(stableHashCode, out var value))
			{
				return null;
			}
			return value;
		}

		private static GameObject? FindScenePrefab(string prefabName)
		{
			if (ZNetScene.instance == null)
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
			if (prefab != null)
			{
				return prefab;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(prefabName);
			if (!ZNetScene.instance.m_namedPrefabs.TryGetValue(stableHashCode, out var value))
			{
				return null;
			}
			return value;
		}

		private static void StoreOriginalIcon(Piece piece)
		{
			if (_originalIcon == null)
			{
				_originalIcon = piece.m_icon;
			}
		}

		private static void StoreOriginalMaterials(GameObject prefab)
		{
			if (_originalMaterials == null)
			{
				_originalMaterials = (from renderer in GetVisualRenderers(prefab)
					select new RendererMaterialSnapshot(renderer, renderer.sharedMaterials.ToArray())).ToList();
			}
		}

		private static void RestoreOriginalMaterials()
		{
			if (_originalMaterials == null)
			{
				return;
			}
			foreach (RendererMaterialSnapshot originalMaterial in _originalMaterials)
			{
				if (originalMaterial.Renderer != null)
				{
					originalMaterial.Renderer.sharedMaterials = originalMaterial.Materials.ToArray();
				}
			}
		}

		private static void ApplyMaterialOverride(GameObject prefab, Material material)
		{
			foreach (Renderer visualRenderer in GetVisualRenderers(prefab))
			{
				Material[] sharedMaterials = visualRenderer.sharedMaterials;
				if (sharedMaterials.Length != 0)
				{
					Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
					for (int i = 0; i < array.Length; i++)
					{
						array[i] = material;
					}
					visualRenderer.sharedMaterials = array;
				}
			}
		}

		private static Material? ResolveMaterial(string materialName)
		{
			string text = NormalizeMaterialName(materialName);
			if (text.Length == 0 || MaterialLookupMissCache.Contains(text))
			{
				return null;
			}
			EnsureMaterialLookupCache(force: false);
			if (TryResolveCachedMaterial(materialName, text, out Material material))
			{
				return material;
			}
			EnsureMaterialLookupCache(force: true);
			if (TryResolveCachedMaterial(materialName, text, out material))
			{
				return material;
			}
			MaterialLookupMissCache.Add(text);
			return null;
		}

		private static bool TryResolveCachedMaterial(string materialName, string normalizedName, out Material? material)
		{
			if (MaterialLookupCache.TryGetValue(materialName, out Material value) && value != null)
			{
				material = value;
				return true;
			}
			if (MaterialLookupCache.TryGetValue(normalizedName, out Material value2) && value2 != null)
			{
				material = value2;
				return true;
			}
			material = null;
			return false;
		}

		private static void EnsureMaterialLookupCache(bool force)
		{
			if (_materialLookupCacheBuilt && !force)
			{
				return;
			}
			MaterialLookupCache.Clear();
			MaterialLookupMissCache.Clear();
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				if (val != null && !string.IsNullOrWhiteSpace(((Object)val).name))
				{
					if (!MaterialLookupCache.ContainsKey(((Object)val).name))
					{
						MaterialLookupCache[((Object)val).name] = val;
					}
					string text = NormalizeMaterialName(((Object)val).name);
					if (text.Length > 0 && !MaterialLookupCache.ContainsKey(text))
					{
						MaterialLookupCache[text] = val;
					}
				}
			}
			_materialLookupCacheBuilt = true;
		}

		private static string NormalizeMaterialName(string name)
		{
			return (name ?? string.Empty).Replace(" (Instance)", string.Empty).Trim();
		}

		private static Sprite? RenderPieceIcon(GameObject sourcePrefab)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Expected O, but got Unknown
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return null;
			}
			GameObject val = null;
			Camera val2 = null;
			Light val3 = null;
			RenderTexture val4 = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				val = SpawnIconRenderClone(sourcePrefab, out List<Renderer> renderers);
				if (val == null || renderers.Count == 0)
				{
					return null;
				}
				Bounds bounds = renderers[0].bounds;
				foreach (Renderer item in renderers.Skip(1))
				{
					((Bounds)(ref bounds)).Encapsulate(item.bounds);
				}
				Vector3 size = ((Bounds)(ref bounds)).size;
				Transform transform = val.transform;
				transform.position -= ((Bounds)(ref bounds)).center;
				val2 = new GameObject("FeedLikeGrandma Feed Barrel Icon Camera", new Type[1] { typeof(Camera) }).GetComponent<Camera>();
				val2.backgroundColor = Color.clear;
				val2.clearFlags = (CameraClearFlags)2;
				val2.fieldOfView = 0.5f;
				val2.farClipPlane = 10000000f;
				val2.cullingMask = 1073741824;
				((Component)val2).transform.rotation = Quaternion.Euler(0f, 180f, 0f);
				val3 = new GameObject("FeedLikeGrandma Feed Barrel Icon Light", new Type[1] { typeof(Light) }).GetComponent<Light>();
				((Component)val3).transform.position = Vector3.zero;
				((Component)val3).transform.rotation = Quaternion.Euler(5f, 180f, 5f);
				val3.type = (LightType)1;
				val3.cullingMask = 1073741824;
				val3.intensity = 1.3f;
				float num = (Mathf.Max(size.x, size.y) + 0.1f) / Mathf.Tan(val2.fieldOfView * ((float)Math.PI / 180f));
				if (float.IsNaN(num) || float.IsInfinity(num) || num <= 0f)
				{
					num = Mathf.Max(size.x, Mathf.Max(size.y, size.z)) + 1f;
				}
				((Component)val2).transform.position = new Vector3(0f, 0f, num);
				val4 = (RenderTexture.active = (val2.targetTexture = RenderTexture.GetTemporary(128, 128, 24, (RenderTextureFormat)0)));
				GL.Clear(true, true, Color.clear);
				val2.Render();
				Texture2D val6 = new Texture2D(128, 128, (TextureFormat)4, false)
				{
					name = "FLG_FeedBarrel_Icon"
				};
				Rect val7 = default(Rect);
				((Rect)(ref val7))..ctor(0f, 0f, 128f, 128f);
				val6.ReadPixels(val7, 0, 0);
				val6.Apply();
				Sprite obj = Sprite.Create(val6, val7, new Vector2(0.5f, 0.5f), 100f);
				((Object)obj).name = ((Object)val6).name;
				return obj;
			}
			catch (Exception ex)
			{
				FeedLikeGrandmaPlugin.Log.LogWarning((object)("FLG_FeedBarrel icon render failed: " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if (val2 != null)
				{
					val2.targetTexture = null;
					DestroyTemporaryObject(((Component)val2).gameObject);
				}
				if (val3 != null)
				{
					DestroyTemporaryObject(((Component)val3).gameObject);
				}
				if ((Object)(object)val4 != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val4);
				}
				if (val != null)
				{
					DestroyTemporaryObject(val);
				}
			}
		}

		private static GameObject? SpawnIconRenderClone(GameObject sourcePrefab, out List<Renderer> renderers)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_0055: 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)
			renderers = new List<Renderer>();
			GameObject val = null;
			try
			{
				val = new GameObject("FLG_FeedBarrel_IconRoot");
				val.SetActive(false);
				GameObject val2 = Object.Instantiate<GameObject>(sourcePrefab, val.transform, false);
				((Object)val2).name = "FLG_FeedBarrel_IconRender";
				StripIconRenderClone(val2);
				val2.transform.SetParent((Transform)null, false);
				Object.DestroyImmediate((Object)(object)val);
				val = null;
				val2.transform.position = Vector3.zero;
				val2.transform.rotation = Quaternion.Euler(23f, 51f, 25.8f);
				SetLayerRecursive(val2, 30);
				val2.SetActive(true);
				renderers = (from renderer in GetVisualRenderers(val2)
					where ((Component)renderer).gameObject.activeInHierarchy
					select renderer).ToList();
				if (renderers.Count == 0)
				{
					DestroyTemporaryObject(val2);
					return null;
				}
				HashSet<Renderer> hashSet = new HashSet<Renderer>(renderers);
				Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val3 in componentsInChildren)
				{
					if (val3 != null && !hashSet.Contains(val3))
					{
						val3.enabled = false;
					}
				}
				return val2;
			}
			catch
			{
				if (val != null)
				{
					Object.DestroyImmediate((Object)(object)val);
				}
				throw;
			}
		}

		private static void StripIconRenderClone(GameObject renderObject)
		{
			Transform[] componentsInChildren = renderObject.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Component[] components = ((Component)componentsInChildren[i]).GetComponents<Component>();
				for (int num = components.Length - 1; num >= 0; num--)
				{
					Component val = components[num];
					if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is MeshFilter) && !(val is MeshRenderer) && !(val is SkinnedMeshRenderer))
					{
						try
						{
							Object.DestroyImmediate((Object)(object)val);
						}
						catch (Exception ex)
						{
							FeedLikeGrandmaPlugin.Log.LogDebug((object)("Could not strip icon render component '" + ((object)val).GetType().Name + "' from '" + ((Object)renderObject).name + "': " + ex.Message));
						}
					}
				}
			}
		}

		private static List<Renderer> GetVisualRenderers(GameObject prefab)
		{
			return (from renderer in prefab.GetComponentsInChildren<Renderer>(true)
				where (Object)(object)renderer != (Object)null && renderer.enabled && !((object)renderer).GetType().Name.Equals("ParticleSystemRenderer", StringComparison.Ordinal)
				select renderer).ToList();
		}

		private static void SetLayerRecursive(GameObject gameObject, int layer)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			gameObject.layer = layer;
			foreach (Transform item in gameObject.transform)
			{
				SetLayerRecursive(((Component)item).gameObject, layer);
			}
		}

		private static void DestroyTemporaryObject(GameObject? gameObject)
		{
			if (gameObject == null)
			{
				return;
			}
			try
			{
				gameObject.SetActive(false);
				Object.DestroyImmediate((Object)(object)gameObject);
			}
			catch (Exception ex)
			{
				FeedLikeGrandmaPlugin.Log.LogDebug((object)("Could not immediately destroy icon render object '" + ((Object)gameObject).name + "': " + ex.Message));
				Object.Destroy((Object)(object)gameObject);
			}
		}

		private static GameObject EnsurePrefabContainer()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (_prefabContainer != null)
			{
				return _prefabContainer;
			}
			_prefabContainer = new GameObject("FeedLikeGrandma Feed Barrel Prefabs");
			_prefabContainer.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_prefabContainer);
			return _prefabContainer;
		}
	}
	internal static class FeedBetterRidingCompatibility
	{
		private const string BetterRidingPluginTypeName = "BetterRiding.BetterRidingPlugin";

		private const string MountStaminaSystemTypeName = "BetterRiding.Behaviour.MountStaminaSystem";

		private const string MountAttackControllerTypeName = "BetterRiding.Behaviour.MountAttackController";

		private const string BetterRidingBlockFlyingDismountPatchTypeName = "BetterRiding.Behaviour.BlockFlyingDismountPatch";

		private const string DragonRidersBlockFlyingDismountPatchTypeName = "DragonRiders.Patches.MountController.BlockFlyingDismountPatch";

		private const float AttackRecordCleanupInterval = 60f;

		private const float AttackRecordTtl = 1800f;

		private static readonly Dictionary<int, float> LastAttackTimes = new Dictionary<int, float>();

		private static readonly Dictionary<string, ConfigEntry<bool>?> BetterRidingBoolConfigEntries = new Dictionary<string, ConfigEntry<bool>>(StringComparer.Ordinal);

		private static readonly List<int> ExpiredAttackKeys = new List<int>();

		private static float _nextAttackRecordCleanupTime;

		private static bool _betterRidingPluginTypeSearched;

		private static Type? _betterRidingPluginType;

		private static bool _mountStaminaSystemTypeSearched;

		private static Type? _mountStaminaSystemType;

		private static bool _mountStaminaSaddleFieldSearched;

		private static FieldInfo? _mountStaminaSaddleField;

		private static int _mountAttackSafetySaddleId;

		private static int _mountAttackSafetyCharacterId;

		private static int _mountAttackSafetyFrame;

		private static bool _mountAttackSafetyAllowed = true;

		private static Type? BetterRidingPluginType
		{
			get
			{
				if (!_betterRidingPluginTypeSearched)
				{
					_betterRidingPluginType = FindType("BetterRiding.BetterRidingPlugin");
					_betterRidingPluginTypeSearched = true;
				}
				return _betterRidingPluginType;
			}
		}

		private static Type? MountStaminaSystemType
		{
			get
			{
				if (!_mountStaminaSystemTypeSearched)
				{
					_mountStaminaSystemType = FindType("BetterRiding.Behaviour.MountStaminaSystem");
					_mountStaminaSystemTypeSearched = true;
				}
				return _mountStaminaSystemType;
			}
		}

		internal static bool HasBetterRiding => BetterRidingPluginType != null;

		internal static bool HasBetterRidingMountStaminaSystem => MountStaminaSystemType != null;

		internal static void Shutdown()
		{
			LastAttackTimes.Clear();
			BetterRidingBoolConfigEntries.Clear();
			ExpiredAttackKeys.Clear();
			_nextAttackRecordCleanupTime = 0f;
			_mountAttackSafetySaddleId = 0;
			_mountAttackSafetyCharacterId = 0;
			_mountAttackSafetyFrame = 0;
			_mountAttackSafetyAllowed = true;
			_betterRidingPluginTypeSearched = false;
			_betterRidingPluginType = null;
			_mountStaminaSystemTypeSearched = false;
			_mountStaminaSystemType = null;
			_mountStaminaSaddleFieldSearched = false;
			_mountStaminaSaddleField = null;
		}

		private static Type? FindType(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(typeName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		internal static MethodBase? GetMountStaminaSystemMethod(string methodName)
		{
			Type mountStaminaSystemType = MountStaminaSystemType;
			if (!(mountStaminaSystemType == null))
			{
				return AccessTools.Method(mountStaminaSystemType, methodName, (Type[])null, (Type[])null);
			}
			return null;
		}

		internal static MethodBase? GetMountAttackUpdate()
		{
			Type type = FindType("BetterRiding.Behaviour.MountAttackController");
			if (!(type == null))
			{
				return AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
			}
			return null;
		}

		internal static MethodBase? GetBetterRidingBlockFlyingDismountPrefix()
		{
			Type type = FindType("BetterRiding.Behaviour.BlockFlyingDismountPatch");
			if (!(type == null))
			{
				return AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null);
			}
			return null;
		}

		internal static MethodBase? GetDragonRidersBlockFlyingDismountPrefix()
		{
			Type type = FindType("DragonRiders.Patches.MountController.BlockFlyingDismountPatch");
			if (!(type == null))
			{
				return AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null);
			}
			return null;
		}

		internal static bool HandleMountedAttack(Humanoid humanoid, ref bool result)
		{
			if (!TryFindAttackSaddle(humanoid, out Sadle saddle) || !TryGetMountStamina(saddle, out ResolvedMountStaminaValues mountStamina) || mountStamina == null)
			{
				return true;
			}
			float time = Time.time;
			CleanupAttackRecords(time);
			int mountKey = GetMountKey(saddle);
			if (mountKey != 0 && LastAttackTimes.TryGetValue(mountKey, out var value) && time - value < mountStamina.AttackCooldown)
			{
				result = false;
				return false;
			}
			if (!CanUseAttackStamina(saddle, mountStamina))
			{
				result = false;
				return false;
			}
			UseAttackStamina(saddle, mountStamina);
			if (mountKey != 0)
			{
				LastAttackTimes[mountKey] = time;
			}
			result = true;
			return false;
		}

		private static void CleanupAttackRecords(float now)
		{
			if (LastAttackTimes.Count == 0 || now < _nextAttackRecordCleanupTime)
			{
				return;
			}
			_nextAttackRecordCleanupTime = now + 60f;
			ExpiredAttackKeys.Clear();
			foreach (KeyValuePair<int, float> lastAttackTime in LastAttackTimes)
			{
				if (now - lastAttackTime.Value > 1800f)
				{
					ExpiredAttackKeys.Add(lastAttackTime.Key);
				}
			}
			foreach (int expiredAttackKey in ExpiredAttackKeys)
			{
				LastAttackTimes.Remove(expiredAttackKey);
			}
			ExpiredAttackKeys.Clear();
		}

		internal static void SuppressPlayerAttackControlsWhileRiding(Player player, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
		{
			if (player != null && ((Character)player).IsRiding())
			{
				attack = false;
				attackHold = false;
				secondaryAttack = false;
				secondaryAttackHold = false;
				ResetPlayerDrawAttack(player);
			}
		}

		internal static bool AllowPlayerAttackInput(Player player)
		{
			if (player == null || !((Character)player).IsRiding())
			{
				return true;
			}
			ResetPlayerDrawAttack(player);
			return false;
		}

		internal static bool CanAttack(object mountStaminaSystem, ref bool result)
		{
			if (!TryGetSystemSaddle(mountStaminaSystem, out Sadle saddle) || !TryGetMountStamina(saddle, out ResolvedMountStaminaValues mountStamina) || mountStamina == null)
			{
				return true;
			}
			result = CanUseAttackStamina(saddle, mountStamina);
			return false;
		}

		internal static bool CanJump(object mountStaminaSystem, ref bool result)
		{
			if (!TryGetSystemSaddle(mountStaminaSystem, out Sadle saddle) || !TryGetMountStamina(saddle, out ResolvedMountStaminaValues mountStamina) || mountStamina == null)
			{
				return true;
			}
			result = CanUseJumpStamina(saddle, mountStamina);
			return false;
		}

		internal static bool OnAttackStart(object mountStaminaSystem)
		{
			if (!TryGetSystemSaddle(mountStaminaSystem, out Sadle saddle) || !TryGetMountStamina(saddle, out ResolvedMountStaminaValues mountStamina) || mountStamina == null)
			{
				return true;
			}
			UseAttackStamina(saddle, mountStamina);
			return false;
		}

		internal static bool OnJumpStart(object mountStaminaSystem)
		{
			if (!TryGetSystemSaddle(mountStaminaSystem, out Sadle saddle) || !TryGetMountStamina(saddle, out ResolvedMountStaminaValues mountStamina) || mountStamina == null)
			{
				return true;
			}
			UseJumpStamina(saddle, mountStamina);
			return false;
		}

		internal static bool AllowMountAttackUpdate()
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer == null)
			{
				return true;
			}
			IDoodadController doodadController = localPlayer.GetDoodadController();
			Sadle val = (Sadle)(object)((doodadController is Sadle) ? doodadController : null);
			if (val == null)
			{
				return true;
			}
			int instanceID = ((Object)val).GetInstanceID();
			Character character = val.GetCharacter();
			if (character == null)
			{
				return true;
			}
			int instanceID2 = ((Object)character).GetInstanceID();
			if (instanceID == _mountAttackSafetySaddleId && instanceID2 == _mountAttackSafetyCharacterId && Time.frameCount - _mountAttackSafetyFrame <= (_mountAttackSafetyAllowed ? 30 : 5))
			{
				return _mountAttackSafetyAllowed;
			}
			bool num = IsMountAttackStateSafe(character);
			_mountAttackSafetySaddleId = instanceID;
			_mountAttackSafetyCharacterId = instanceID2;
			_mountAttackSafetyFrame = Time.frameCount;
			_mountAttackSafetyAllowed = num;
			return num;
		}

		internal static bool AllowBlockFlyingDismount(Player player, ref bool result)
		{
			if (!ShouldAllowWaterDismount(player))
			{
				return true;
			}
			result = true;
			return false;
		}

		private static bool IsMountAttackStateSafe(Character character)
		{
			Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (val == null)
			{
				return true;
			}
			if (character.m_baseAI != null && val.m_defaultItems != null)
			{
				return val.m_defaultItems.Length >= 2;
			}
			return false;
		}

		private static bool ShouldAllowWaterDismount(Player player)
		{
			if (player == null || !((Character)player).IsRiding())
			{
				return false;
			}
			IDoodadController doodadController = player.m_doodadController;
			IDoodadController obj = ((doodadController is Sadle) ? doodadController : null);
			Character character = ((obj != null) ? ((Sadle)obj).GetCharacter() : null);
			if (obj != null)
			{
				if (!IsInWater((Character?)(object)player))
				{
					return IsInWater(character);
				}
				return true;
			}
			return false;
		}

		private static bool IsInWater(Character? character)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (character == null)
			{
				return false;
			}
			if (!character.InWater())
			{
				if (character.m_waterLevel > character.m_tarLevel)
				{
					return character.m_waterLevel - ((Component)character).transform.position.y > 0.05f;
				}
				return false;
			}
			return true;
		}

		private static void ResetPlayerDrawAttack(Player player)
		{
			if (!(((Humanoid)player).m_attackDrawTime <= 0f))
			{
				string text = ((Humanoid)player).GetCurrentWeapon()?.m_shared.m_attack.m_drawAnimationState;
				if (!string.IsNullOrEmpty(text))
				{
					((Character)player).m_zanim.SetBool(text, false);
					((Character)player).m_zanim.SetFloat("drawpercent", 0f);
				}
				((Humanoid)player).m_attackDrawTime = 0f;
			}
		}

		private static bool CanUseAttackStamina(Sadle? saddle, ResolvedMountStaminaValues mountStamina)
		{
			if (GetBetterRidingBoolConfig("EnableAttackStaminaDrain", fallback: true))
			{
				return CanUseStamina(saddle, mountStamina.AttackStaminaCost);
			}
			return true;
		}

		private static bool CanUseJumpStamina(Sadle? saddle, ResolvedMountStaminaValues mountStamina)
		{
			if (GetBetterRidingBoolConfig("EnableJumpStaminaDrain", fallback: true))
			{
				return CanUseStamina(saddle, mountStamina.JumpStaminaCost);
			}
			return true;
		}

		private static void UseAttackStamina(Sadle? saddle, ResolvedMountStaminaValues mountStamina)
		{
			if (GetBetterRidingBoolConfig("EnableAttackStaminaDrain", fallback: true))
			{
				UseStaminaDirect(saddle, mountStamina.AttackStaminaCost);
			}
		}

		private static void UseJumpStamina(Sadle? saddle, ResolvedMountStaminaValues mountStamina)
		{
			if (GetBetterRidingBoolConfig("EnableJumpStaminaDrain", fallback: true))
			{
				UseStaminaDirect(saddle, mountStamina.JumpStaminaCost);
			}
		}

		private static bool CanUseStamina(Sadle? saddle, float amount)
		{
			if (saddle != null && saddle.m_nview != null && saddle.m_nview.IsValid())
			{
				return saddle.GetStamina() >= amount;
			}
			return false;
		}

		private static void UseStaminaDirect(Sadle? saddle, float amount)
		{
			if (!(amount <= 0f) && saddle != null && saddle.m_nview != null && saddle.m_nview.IsValid() && saddle.m_nview.IsOwner())
			{
				float stamina = saddle.GetStamina();
				if (!(stamina < amount))
				{
					saddle.SetStamina(Mathf.Max(0f, stamina - amount));
				}
			}
		}

		private static bool TryGetSystemSaddle(object mountStaminaSystem, out Sadle? saddle)
		{
			saddle = null;
			if (mountStaminaSystem == null)
			{
				return false;
			}
			FieldInfo mountStaminaSaddleField = GetMountStaminaSaddleField();
			if (mountStaminaSaddleField == null)
			{
				return false;
			}
			object? value = mountStaminaSaddleField.GetValue(mountStaminaSystem);
			saddle = (Sadle?)((value is Sadle) ? value : null);
			return saddle != null;
		}

		private static bool TryFindAttackSaddle(Humanoid humanoid, out Sadle? saddle)
		{
			saddle = null;
			if (humanoid == null)
			{
				return false;
			}
			Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
			if (val != null && ((Character)val).IsRiding())
			{
				IDoodadController doodadController = val.m_doodadController;
				saddle = (Sadle?)(object)((doodadController is Sadle) ? doodadController : null);
				return saddle != null;
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer == null || !((Character)localPlayer).IsRiding())
			{
				return false;
			}
			IDoodadController doodadController2 = localPlayer.m_doodadController;
			saddle = (Sadle?)(object)((doodadController2 is Sadle) ? doodadController2 : null);
			Sadle? obj = saddle;
			Character val2 = ((obj != null) ? obj.GetCharacter() : null);
			if (val2 == null || (object)val2 != humanoid)
			{
				saddle = null;
				return false;
			}
			return true;
		}

		private static bool TryGetMountStamina(Sadle? saddle, out ResolvedMountStaminaValues? mountStamina)
		{
			mountStamina = null;
			if (saddle == null)
			{
				return false;
			}
			Character character = saddle.GetCharacter();
			if (character != null)
			{
				return FeedSystem.TryGetMountStamina(character, out mountStamina);
			}
			return false;
		}

		private static int GetMountKey(Sadle? saddle)
		{
			if (saddle == null)
			{
				return 0;
			}
			Character character = saddle.GetCharacter();
			if (character != null)
			{
				return ((Object)((Component)character).gameObject).GetInstanceID();
			}
			return 0;
		}

		private static bool GetBetterRidingBoolConfig(string fieldName, bool fallback)
		{
			if (!BetterRidingBoolConfigEntries.TryGetValue(fieldName, out ConfigEntry<bool> value))
			{
				Type betterRidingPluginType = BetterRidingPluginType;
				value = ((betterRidingPluginType == null) ? null : AccessTools.Field(betterRidingPluginType, fieldName)?.GetValue(null)) as ConfigEntry<bool>;
				BetterRidingBoolConfigEntries[fieldName] = value;
			}
			return value?.Value ?? fallback;
		}

		private static FieldInfo? GetMountStaminaSaddleField()
		{
			if (!_mountStaminaSaddleFieldSearched)
			{
				Type mountStaminaSystemType = MountStaminaSystemType;
				_mountStaminaSaddleField = ((mountStaminaSystemType == null) ? null : AccessTools.Field(mountStaminaSystemType, "m_saddle"));
				_mountStaminaSaddleFieldSearched = true;
			}
			return _mountStaminaSaddleField;
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class BetterRidingSuppressPlayerAttackHoldPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.HasBetterRiding;
		}

		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "Yggdrah.BetterRiding" })]
		private static void Prefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
		{
			FeedBetterRidingCompatibility.SuppressPlayerAttackControlsWhileRiding(__instance, ref attack, ref attackHold, ref secondaryAttack, ref secondaryAttackHold);
		}
	}
	[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
	internal static class BetterRidingSuppressPlayerAttackInputPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.HasBetterRiding;
		}

		private static bool Prefix(Player __instance)
		{
			return FeedBetterRidingCompatibility.AllowPlayerAttackInput(__instance);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingHandleMountedAttackPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("HandleMountedAttack") != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("HandleMountedAttack");
		}

		private static bool Prefix(Humanoid instance, ref bool __result)
		{
			return FeedBetterRidingCompatibility.HandleMountedAttack(instance, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingCanAttackPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("CanAttack") != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("CanAttack");
		}

		private static bool Prefix(object __instance, ref bool __result)
		{
			return FeedBetterRidingCompatibility.CanAttack(__instance, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingCanJumpPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("CanJump") != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("CanJump");
		}

		private static bool Prefix(object __instance, ref bool __result)
		{
			return FeedBetterRidingCompatibility.CanJump(__instance, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingOnAttackStartPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("OnAttackStart") != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("OnAttackStart");
		}

		private static bool Prefix(object __instance)
		{
			return FeedBetterRidingCompatibility.OnAttackStart(__instance);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingOnJumpStartPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("OnJumpStart") != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountStaminaSystemMethod("OnJumpStart");
		}

		private static bool Prefix(object __instance)
		{
			return FeedBetterRidingCompatibility.OnJumpStart(__instance);
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingMountAttackSafetyPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetMountAttackUpdate() != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetMountAttackUpdate();
		}

		private static bool Prefix()
		{
			return FeedBetterRidingCompatibility.AllowMountAttackUpdate();
		}
	}
	[HarmonyPatch]
	internal static class BetterRidingBlockFlyingDismountWaterPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetBetterRidingBlockFlyingDismountPrefix() != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetBetterRidingBlockFlyingDismountPrefix();
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Player __0, ref bool __result)
		{
			return FeedBetterRidingCompatibility.AllowBlockFlyingDismount(__0, ref __result);
		}
	}
	[HarmonyPatch]
	internal static class DragonRidersBlockFlyingDismountWaterPatch
	{
		private static bool Prepare()
		{
			return FeedBetterRidingCompatibility.GetDragonRidersBlockFlyingDismountPrefix() != null;
		}

		private static MethodBase? TargetMethod()
		{
			return FeedBetterRidingCompatibility.GetDragonRidersBlockFlyingDismountPrefix();
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Player __0, ref bool __result)
		{
			return FeedBetterRidingCompatibility.AllowBlockFlyingDismount(__0, ref __result);
		}
	}
	internal sealed class RawFeedConfig
	{
		public Dictionary<string, RawFeedingRule> Rules { get; } = new Dictionary<string, RawFeedingRule>(StringComparer.OrdinalIgnoreCase);

		public Dictionary<string, float> FoodNumbers { get; } = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		public RawFeedValues Defaults { get; set; } = new RawFeedValues();
	}
	internal sealed class RawFoodEntry
	{
		public string PrefabName { get; init; } = string.Empty;

		public int? RequiredQuality { get; init; }

		public float? Value { get; init; }

		public bool DefaultToOne { get; init; }
	}
	internal sealed class RawFeedValues
	{
		public float LevelUpConstant { get; init; } = 1f;

		public float TamingConstant { get; init; } = 1f;

		public float GrowthConstant { get; init; } = 1f;

		public float HealConstant { get; init; } = 1f;

		public float FedConstant { get; init; } = 60f;
	}
	internal sealed class RawTameValues
	{
		public float FedDuration { get; init; }

		public float TamingTime { get; init; }

		public bool StartsTamed { get; init; }

		public bool Commandable { get; init; }
	}
	internal sealed class RawProcreationValues
	{
		public int MaxCreatures { get; init; }

		public float TotalCheckRange { get; init; }
	}
	internal sealed class RawGrowValues
	{
		public float GrowTime { get; init; }
	}
	internal sealed class RawEggGrowValues
	{
		public float GrowTime { get; init; }
	}
	internal sealed class RawMountStaminaValues
	{
		public float AttackStaminaCost { get; init; }

		public float JumpStaminaCost { get; init; }

		public float AttackCooldown { get; init; }
	}
	internal sealed class RawFeedingRule
	{
		public string PrefabName { get; init; } = string.Empty;

		public RawFeedValues? Feed { get; set; }

		public RawTameValues? Tame { get; set; }

		public RawProcreationValues? Procreation { get; set; }

		public RawGrowValues? Grow { get; set; }

		public RawEggGrowValues? EggGrow { get; set; }

		public RawMountStaminaValues? MountStamina { get; set; }

		public bool HasRestrictedBiomeOverride { get; set; }

		public List<string> RestrictedBiomes { get; } = new List<string>();

		public List<RawFoodEntry> Foods { get; } = new List<RawFoodEntry>();

		public List<string> ConsumeItems { get; } = new List<string>();

		public Dictionary<int, List<RawFoodEntry>> LevelUpItems { get; } = new Dictionary<int, List<RawFoodEntry>>();
	}
	internal sealed class ResolvedFoodEntry
	{
		public string PrefabName { get; init; } = string.Empty;

		public int? RequiredQuality { get; init; }

		public float Value { get; init; }

		public Sprite Icon { get; init; }
	}
	internal sealed class ResolvedFeedingRule
	{
		public GameObject Prefab { get; init; }

		public float LevelUpConstant { get; init; }

		public float TamingConstant { get; init; }

		public float GrowthConstant { get; init; }

		public float HealConstant { get; init; }

		public float FedConstant { get; init; }

		public List<ResolvedFoodEntry> Foods { get; init; } = new List<ResolvedFoodEntry>();

		public Dictionary<int, List<ResolvedFoodEntry>> LevelUpItems { get; init; } = new Dictionary<int, List<ResolvedFoodEntry>>();

		public ResolvedMountStaminaValues? MountStamina { get; init; }

		public bool HasRestrictedBiomeOverride { get; init; }

		public IReadOnlyList<string> RestrictedBiomes { get; init; } = Array.Empty<string>();
	}
	internal sealed class ResolvedMountStaminaValues
	{
		public float AttackStaminaCost { get; init; }

		public float JumpStaminaCost { get; init; }

		public float AttackCooldown { get; init; }
	}
	internal static class FeedingYamlParser
	{
		public static RawFeedConfig Parse(string yamlText, List<string> warnings)
		{
			RawFeedConfig rawFeedConfig = new RawFeedConfig();
			if (string.IsNullOrWhiteSpace(yamlText))
			{
				return rawFeedConfig;
			}
			YamlStream yamlStream = new YamlStream();
			yamlStream.Load(new StringReader(yamlText));
			if (yamlStream.Documents.Count == 0 || !(yamlStream.Documents[0].RootNode is YamlMappingNode yamlMappingNode))
			{
				warnings.Add("YAML root must be a mapping of defaults, foodNumbers, and prefab names.");
				return rawFeedConfig;
			}
			foreach (KeyValuePair<YamlNode, YamlNode> child in yamlMappingNode.Children)
			{
				string text = ReadScalar(child.Key).Trim();
				if (text.Length == 0)
				{
					warnings.Add(Location(child.Key) + ": top-level key cannot be empty.");
					continue;
				}
				if (text.Equals("defaults", StringComparison.OrdinalIgnoreCase))
				{
					ParseDefaults(rawFeedConfig, child.Value, warnings);
					continue;
				}
				if (text.Equals("foodNumbers", StringComparison.OrdinalIgnoreCase))
				{
					ParseFoodNumbers(rawFeedConfig.FoodNumbers, child.Value, "foodNumbers", warnings);
					continue;
				}
				RawFeedingRule value = ParseRule(text, child.Value, warnings);
				if (rawFeedConfig.Rules.ContainsKey(text))
				{
					warnings.Add(Location(child.Key) + ": prefab '" + text + "' was defined more than once. The last definition won.");
				}
				rawFeedConfig.Rules[text] = value;
			}
			return rawFeedConfig;
		}

		private static void ParseDefaults(RawFeedConfig config, YamlNode node, List<string> warnings)
		{
			if (!(node is YamlMappingNode yamlMappingNode))
			{
				warnings.Add(Location(node) + ": defaults must be a mapping.");
				return;
			}
			foreach (KeyValuePair<YamlNode, YamlNode> child in yamlMappingNode.Children)
			{
				string text = ReadScalar(child.Key).Trim();
				if (text.Equals("feed", StringComparison.OrdinalIgnoreCase))
				{
					config.Defaults = ParseFeedValues(child.Value, "defaults.feed", warnings);
				}
				else
				{
					warnings.Add(Location(child.Key) + ": unknown defaults field '" + text + "'.");
				}
			}
		}

		private static RawFeedingRule ParseRule(string prefabName, YamlNode node, List<string> warnings)
		{
			RawFeedingRule rawFeedingRule = new RawFeedingRule
			{
				PrefabName = prefabName
			};
			if (!(node is YamlMappingNode yamlMappingNode))
			{
				warnings.Add(Location(node) + ": prefab '" + prefabName + "' must contain a mapping.");
				return rawFeedingRule;
			}
			foreach (KeyValuePair<YamlNode, YamlNode> child in yamlMappingNode.Children)
			{
				string text = ReadScalar(child.Key).Trim();
				switch (NormalizeField(text))
				{
				case "feed":
					rawFeedingRule.Feed = ParseFeedValues(child.Value, prefabName + ".feed", warnings);
					break;
				case "consumeitems":
					ParseConsumeItems(rawFeedingRule, child.Value, warnings);
					break;
				case "levelupitems":
					ParseLevelUpItems(rawFeedingRule, child.Value, prefabName + ".levelUpItems", warnings);
					break;
				case "tame":
					rawFeedingRule.Tame = ParseTameValues(child.Value, prefabName + ".tame", warnings);
					break;
				case "procreation":
					rawFeedingRule.Procreation = ParseProcreationValues(child.Value, prefabName + ".procreation", warnings);
					break;
				case "grow":
					rawFeedingRule.Grow = ParseGrowValues(child.Value, prefabName + ".grow", warnings);
					break;
				case "egggrow":
					rawFeedingRule.EggGrow = ParseEggGrowValues(child.Value, prefabName + ".eggGrow", warnings);
					break;
				case "mountstamina":
					rawFeedingRule.MountStamina = ParseMountStaminaValues(child.Value, prefabName + ".mountStamina", warnings);
					break;
				case "restrictedbiome":
				case "restrictedbiomes":
					rawFeedingRule.HasRestrictedBiomeOverride = true;
					rawFeedingRule.RestrictedBiomes.Clear();
					rawFeedingRule.RestrictedBiomes.AddRange((from value in ParseStringList(child.Value)
						select Unquote(value).Trim() into value
						where value.Length > 0
						select value).Distinct<string>(StringComparer.OrdinalIgnoreCase));
					break;
				default:
					warnings.Add(Location(child.Key) + ": unknown field '" + text + "' for prefab '" + prefabName + "'.");
					break;
				}
			}
			return rawFeedingRule;
		}

		private static void ParseConsumeItems(RawFeedingRule rule, YamlNode node, List<string> warnings)
		{
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				{
					foreach (YamlNode child in yamlSequenceNode.Children)
					{
						AddConsumeItemEntry(rule, child, warnings);
					}
					return;
				}
			}
			foreach (string item in ParseStringList(node))
			{
				AddConsumeItemEntry(rule, item, node, warnings);
			}
		}

		private static void AddConsumeItemEntry(RawFeedingRule rule, YamlNode node, List<string> warnings)
		{
			if (node is YamlMappingNode yamlMappingNode && yamlMappingNode.Children.Count == 1)
			{
				KeyValuePair<YamlNode, YamlNode> keyValuePair = yamlMappingNode.Children.First();
				AddFoodEntry(rule, ReadScalar(keyValuePair.Key).Trim(), ReadScalar(keyValuePair.Value).Trim(), defaultToOne: true, node, warnings);
				AddConsumeItem(rule, ReadScalar(keyValuePair.Key).Trim(), node, warnings);
				return;
			}
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				List<string> list = yamlSequenceNode.Children.Select((YamlNode child) => ReadScalar(child).Trim()).ToList();
				if (list.Count >= 2)
				{
					AddFoodEntry(rule, list[0], list[1], defaultToOne: true, node, warnings);
					AddConsumeItem(rule, list[0], node, warnings);
					return;
				}
			}
			AddConsumeItemEntry(rule, ReadScalar(node).Trim(), node, warnings);
		}

		private static void AddConsumeItemEntry(RawFeedingRule rule, string entryText, YamlNode node, List<string> warnings)
		{
			string valueText = null;
			string foodName;
			if (TrySplitCommaValue(entryText, out string key, out string value))
			{
				foodName = Unquote(key).Trim();
				valueText = value;
			}
			else
			{
				foodName = Unquote(entryText).Trim();
			}
			AddFoodEntry(rule, foodName, valueText, defaultToOne: true, node, warnings);
			AddConsumeItem(rule, foodName, node, warnings);
		}

		private static void AddFoodEntry(RawFeedingRule rule, string foodName, string? valueText, bool defaultToOne, YamlNode node, List<string> warnings)
		{
			AddFoodEntry(rule.Foods, rule.PrefabName, foodName, valueText, defaultToOne, node, warnings);
		}

		private static void AddFoodEntry(List<RawFoodEntry> foods, string ruleName, string foodName, string? valueText, bool defaultToOne, YamlNode node, List<string> warnings)
		{
			string prefabName;
			int? requiredQuality;
			if (string.IsNullOrWhiteSpace(foodName))
			{
				warnings.Add(Location(node) + ": food item name cannot be empty.");
			}
			else if (TryParseFoodToken(foodName, node, warnings, out prefabName, out requiredQuality))
			{
				float? value = null;
				if (!string.IsNullOrWhiteSpace(valueText))
				{
					value = Math.Max(0f, ParseFloat(valueText, ruleName + "." + FormatFoodKey(prefabName, requiredQuality), node, warnings));
				}
				int num = foods.FindIndex((RawFoodEntry entry) => entry.PrefabName.Equals(prefabName, StringComparison.OrdinalIgnoreCase) && entry.RequiredQuality == requiredQuality);
				if (num >= 0)
				{
					warnings.Add(Location(node) + ": food '" + FormatFoodKey(prefabName, requiredQuality) + "' was defined more than once for '" + ruleName + "'. The last value won.");
					foods.RemoveAt(num);
				}
				foods.Add(new RawFoodEntry
				{
					PrefabName = prefabName,
					RequiredQuality = requiredQuality,
					Value = value,
					DefaultToOne = defaultToOne
				});
			}
		}

		private static void AddConsumeItem(RawFeedingRule rule, string foodName, YamlNode node, List<string> warnings)
		{
			if (!string.IsNullOrWhiteSpace(foodName) && TryParseFoodToken(foodName, node, warnings, out string prefabName, out int? _) && rule.ConsumeItems.FindIndex((string entry) => entry.Equals(prefabName, StringComparison.OrdinalIgnoreCase)) < 0)
			{
				rule.ConsumeItems.Add(prefabName);
			}
		}

		private static void ParseLevelUpItems(RawFeedingRule rule, YamlNode node, string context, List<string> warnings)
		{
			if (!(node is YamlMappingNode yamlMappingNode))
			{
				warnings.Add(Location(node) + ": " + context + " must be a mapping of current Character level to consumeItems.");
				return;
			}
			foreach (KeyValuePair<YamlNode, YamlNode> child in yamlMappingNode.Children)
			{
				int num = Math.Max(1, ParseInt(child.Key, context + ".level", warnings));
				List<RawFoodEntry> list = new List<RawFoodEntry>();
				if (child.Value is YamlSequenceNode yamlSequenceNode)
				{
					foreach (YamlNode child2 in yamlSequenceNode.Children)
					{
						AddLevelUpConsumeItemEntry(list, $"{rule.PrefabName}.levelUpItems.{num}", child2, warnings);
					}
				}
				else
				{
					foreach (string item in ParseStringList(child.Value))
					{
						AddLevelUpConsumeItemEntry(list, $"{rule.PrefabName}.levelUpItems.{num}", item, child.Value, warnings);
					}
				}
				if (rule.LevelUpItems.ContainsKey(num))
				{
					warnings.Add($"{Location(child.Key)}: levelUpItems for Character level {num} was defined more than once for prefab '{rule.PrefabName}'. The last definition won.");
				}
				rule.LevelUpItems[num] = list;
			}
		}

		private static void AddLevelUpConsumeItemEntry(List<RawFoodEntry> foods, string context, YamlNode node, List<string> warnings)
		{
			if (node is YamlMappingNode yamlMappingNode && yamlMappingNode.Children.Count == 1)
			{
				KeyValuePair<YamlNode, YamlNode> keyValuePair = yamlMappingNode.Children.First();
				AddFoodEntry(foods, context, ReadScalar(keyValuePair.Key).Trim(), ReadScalar(keyValuePair.Value).Trim(), defaultToOne: true, node, warnings);
				return;
			}
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				List<string> list = yamlSequenceNode.Children.Select((YamlNode child) => ReadScalar(child).Trim()).ToList();
				if (list.Count >= 2)
				{
					AddFoodEntry(foods, context, list[0], list[1], defaultToOne: true, node, warnings);
					return;
				}
			}
			AddLevelUpConsumeItemEntry(foods, context, ReadScalar(node).Trim(), node, warnings);
		}

		private static void AddLevelUpConsumeItemEntry(List<RawFoodEntry> foods, string context, string entryText, YamlNode node, List<string> warnings)
		{
			string valueText = null;
			string foodName;
			if (TrySplitCommaValue(entryText, out string key, out string value))
			{
				foodName = Unquote(key).Trim();
				valueText = value;
			}
			else
			{
				foodName = Unquote(entryText).Trim();
			}
			AddFoodEntry(foods, context, foodName, valueText, defaultToOne: true, node, warnings);
		}

		private static void ParseFoodNumbers(Dictionary<string, float> foodNumbers, YamlNode node, string context, List<string> warnings)
		{
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				{
					foreach (YamlNode child in yamlSequenceNode.Children)
					{
						AddFoodNumber(foodNumbers, child, context, warnings);
					}
					return;
				}
			}
			warnings.Add(Location(node) + ": " + context + " must be a sequence. Use entries like '- Raspberry' or '- Raspberry, 3'.");
		}

		private static void AddFoodNumber(Dictionary<string, float> foodNumbers, YamlNode node, string context, List<string> warnings)
		{
			string text = ReadScalar(node).Trim();
			string key;
			string value;
			bool flag = TrySplitCommaValue(text, out key, out value);
			if (TryParseFoodToken(Unquote(flag ? key : text).Trim(), node, warnings, out string prefabName, out int? requiredQuality))
			{
				string text2 = FormatFoodKey(prefabName, requiredQuality);
				foodNumbers[text2] = (flag ? Math.Max(0f, ParseFloat(value, context + "." + text2, node, warnings)) : 1f);
			}
		}

		internal static string FormatFoodKey(string prefabName, int? requiredQuality)
		{
			if (!requiredQuality.HasValue)
			{
				return prefabName;
			}
			return prefabName + "@" + requiredQuality.Value.ToString(CultureInfo.InvariantCulture);
		}

		private static bool TryParseFoodToken(string foodName, YamlNode node, List<string> warnings, out string prefabName, out int? requiredQuality)
		{
			prefabName = Unquote(foodName).Trim();
			requiredQuality = null;
			if (prefabName.Length == 0)
			{
				warnings.Add(Location(node) + ": food item name cannot be empty.");
				return false;
			}
			int num = prefabName.LastIndexOf('@');
			if (num < 0)
			{
				return true;
			}
			string text = prefabName.Substring(0, num).Trim();
			string s = prefabName.Substring(num + 1).Trim();
			if (text.Length == 0 || !int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result <= 0)
			{
				warnings.Add(Location(node) + ": food item '" + foodName + "' must use ItemName@quality with a positive integer quality.");
				prefabName = string.Empty;
				return false;
			}
			prefabName = text;
			requiredQuality = result;
			return true;
		}

		private static RawFeedValues ParseFeedValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 5)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 5 values: levelupconstant, tamingconstant, growthconstant, healconstant, fedconstant.");
				return new RawFeedValues();
			}
			return new RawFeedValues
			{
				LevelUpConstant = Math.Max(0f, ParseFloat(list[0], field + ".levelupconstant", node, warnings)),
				TamingConstant = Math.Max(0f, ParseFloat(list[1], field + ".tamingconstant", node, warnings)),
				GrowthConstant = Math.Max(0f, ParseFloat(list[2], field + ".growthconstant", node, warnings)),
				HealConstant = Math.Max(0f, ParseFloat(list[3], field + ".healconstant", node, warnings)),
				FedConstant = Math.Max(0f, ParseFloat(list[4], field + ".fedconstant", node, warnings))
			};
		}

		private static RawTameValues? ParseTameValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 4)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 4 values: fedDuration, tamingTime, startsTamed, commandable.");
				return null;
			}
			return new RawTameValues
			{
				FedDuration = Math.Max(0f, ParseFloat(list[0], field + ".fedDuration", node, warnings)),
				TamingTime = Math.Max(0f, ParseFloat(list[1], field + ".tamingTime", node, warnings)),
				StartsTamed = ParseBool(list[2], field + ".startsTamed", node, warnings),
				Commandable = ParseBool(list[3], field + ".commandable", node, warnings)
			};
		}

		private static RawProcreationValues? ParseProcreationValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 2)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 2 values: maxCreatures, totalCheckRange.");
				return null;
			}
			return new RawProcreationValues
			{
				MaxCreatures = Math.Max(0, ParseInt(list[0], field + ".maxCreatures", node, warnings)),
				TotalCheckRange = Math.Max(0f, ParseFloat(list[1], field + ".totalCheckRange", node, warnings))
			};
		}

		private static RawGrowValues? ParseGrowValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 1)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 1 value: growTime.");
				return null;
			}
			return new RawGrowValues
			{
				GrowTime = Math.Max(0f, ParseFloat(list[0], field + ".growTime", node, warnings))
			};
		}

		private static RawEggGrowValues? ParseEggGrowValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 1)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 1 value: growTime.");
				return null;
			}
			return new RawEggGrowValues
			{
				GrowTime = Math.Max(0f, ParseFloat(list[0], field + ".growTime", node, warnings))
			};
		}

		private static RawMountStaminaValues? ParseMountStaminaValues(YamlNode node, string field, List<string> warnings)
		{
			List<string> list = ReadTupleParts(node);
			if (list.Count != 3)
			{
				warnings.Add(Location(node) + ": field '" + field + "' must contain 3 values: attackStaminaCost, jumpStaminaCost, attackCooldown.");
				return null;
			}
			return new RawMountStaminaValues
			{
				AttackStaminaCost = Math.Max(0f, ParseFloat(list[0], field + ".attackStaminaCost", node, warnings)),
				JumpStaminaCost = Math.Max(0f, ParseFloat(list[1], field + ".jumpStaminaCost", node, warnings)),
				AttackCooldown = Math.Max(0f, ParseFloat(list[2], field + ".attackCooldown", node, warnings))
			};
		}

		private static List<string> ParseStringList(YamlNode node)
		{
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				return (from child in yamlSequenceNode.Children
					select ReadScalar(child).Trim() into value
					where value.Length > 0
					select value).ToList();
			}
			string text = ReadScalar(node).Trim();
			if (text.Length == 0)
			{
				return new List<string>();
			}
			if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal))
			{
				return (from part in SplitCommaText(text.Substring(1, text.Length - 2))
					select Unquote(part).Trim() into value
					where value.Length > 0
					select value).ToList();
			}
			return new List<string> { Unquote(text) };
		}

		private static List<string> ReadTupleParts(YamlNode node)
		{
			if (node is YamlSequenceNode yamlSequenceNode)
			{
				return yamlSequenceNode.Children.Select((YamlNode child) => ReadScalar(child).Trim()).ToList();
			}
			string text = ReadScalar(node).Trim();
			if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal))
			{
				text = text.Substring(1, text.Length - 2);
			}
			return (from part in SplitCommaText(text)
				select Unquote(part).Trim()).ToList();
		}

		private static int ParseInt(YamlNode node, string field, List<string> warnings)
		{
			return ParseInt(ReadScalar(node), field, node, warnings);
		}

		private static int ParseInt(string valueText, string field, YamlNode node, List<string> warnings)
		{
			if (int.TryParse(Unquote(valueText).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			warnings.Add(Location(node) + ": field '" + field + "' must be an integer.");
			return 0;
		}

		private static float ParseFloat(YamlNode node, string field, List<string> warnings)
		{
			return ParseFloat(ReadScalar(node), field, node, warnings);
		}

		private static float ParseFloat(string valueText, string field, YamlNode node, List<string> warnings)
		{
			if (float.TryParse(Unquote(valueText).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			warnings.Add(Location(node) + ": field '" + field + "' must be a number.");
			return 0f;
		}

		private static bool ParseBool(string valueText, string field, YamlNode node, List<string> warnings)
		{
			string text = Unquote(valueText).Trim();
			if (bool.TryParse(text, out var result))
			{
				return result;
			}
			string text2 = text.ToLowerInvariant();
			if (text2 != null)
			{
				switch (text2.Length)
				{
				case 1:
				{
					char c = text2[0];
					if ((uint)c <= 49u)
					{
						if (c != '0')
						{
							if (c != '1')
							{
								break;
							}
							goto IL_00dd;
						}
					}
					else if (c != 'n')
					{
						if (c != 'y')
						{
							break;
						}
						goto IL_00dd;
					}
					goto IL_00df;
				}
				case 3:
				{
					char c = text2[0];
					if (c != 'o')
					{
						if (c != 'y' || !(text2 == "yes"))
						{
							break;
						}
						goto IL_00dd;
					}
					if (!(text2 == "off"))
					{
						break;
					}
					goto IL_00df;
				}
				case 2:
					{
						char c = text2[0];
						if (c != 'n')
						{
							if (c != 'o' || !(text2 == "on"))
							{
								break;
							}
							goto IL_00dd;
						}
						if (!(text2 == "no"))
						{
							break;
						}
						goto IL_00df;
					}
					IL_00df:
					return false;
					IL_00dd:
					return true;
				}
			}
			warnings.Add(Location(node) + ": field '" + field + "' must be true or false.");
			return false;
		}

		private static string ReadScalar(YamlNode node)
		{
			object obj;
			if (!(node is YamlScalarNode yamlScalarNode))
			{
				obj = node.ToString();
				if (obj == null)
				{
					return string.Empty;
				}
			}
			else
			{
				obj = yamlScalarNode.Value ?? string.Empty;
			}
			return (string)obj;
		}

		private static string NormalizeField(string field)
		{
			return field.Replace("_", string.Empty).Replace("-", string.Empty).Trim()
				.ToLowerInvariant();
		}

		private static bool TrySplitCommaValue(string text, out string key, out string value)
		{
			List<string> list = SplitCommaText(text);
			if (list.Count < 2)
			{
				key = string.Empty;
				value = string.Empty;
				return false;
			}
			key = list[0].Trim();
			value = list[1].Trim();
			return key.Length > 0;
		}

		private static List<string> SplitCommaText(string text)
		{
			List<string> list = new List<string>();
			bool flag = false;
			bool flag2 = false;
			int num = 0;
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (c == '\'' && !flag2)
				{
					flag = !flag;
				}
				else if (c == '"' && !flag)
				{
					flag2 = !flag2;
				}
				else if (!(c != ',' || flag || flag2))
				{
					list.Add(text.Substring(num, i - num).Trim());
					num = i + 1;
				}
			}
			list.Add(text.Substring(num).Trim());
			return list;
		}

		private static string Unquote(string text)
		{
			text = text.Trim();
			if (text.Length >= 2 && ((text[0] == '"' && text[text.Length - 1] == '"') || (text[0] == '\'' && text[text.Length - 1] == '\'')))
			{
				return text.Substring(1, text.Length - 2).Replace("''", "'");
			}
			return text;
		}

		private static string Location(YamlNode node)
		{
			if (node.Start.Line <= 0)
			{
				return "YAML";
			}
			return $"Line {node.Start.Line}";
		}
	}
	internal static class FeedDragonFlightRestrictionSystem
	{
		private sealed class RestrictionState
		{
			public int MountId { get; init; }

			public Biome Biome { get; init; }

			public bool Restricted { get; init; }
		}

		private const string FlightControlsTypeName = "BetterRiding.Behaviour.FlightControls";

		private const string FlightControlsPlayerSetControlsPatchTypeName = "BetterRiding.Behaviour.FlightControls+Ygg_PlayerSetControls";

		private const string MountControllerTypeName = "BetterRiding.Behaviour.MountController";

		private const string MountControllerPlayerUpdatePatchTypeName = "BetterRiding.Behaviour.MountController+Player_Update_Patch";

		private const string ExpandWorldBiomeManagerTypeName = "ExpandWorldData.BiomeManager";

		private const string BiomeRestrictedMessage = "$flg_dragon_flight_restricted";

		private const string EncumberedRestrictedMessage = "$flg_dragon_flight_encumbered";

		private static readonly Dictionary<int, RestrictionState> PlayerStates = new Dictionary<int, RestrictionState>();

		private static readonly Dictionary<string, Biome> ResolvedBiomeNames = new Dictionary<string, Biome>(StringComparer.OrdinalIgnoreCase);

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

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

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

		private static readonly Dictionary<string, ConfigEntry<KeyCode>?> FlightKeyConfigCache = new Dictionary<string, ConfigEntry<KeyCode>>(StringComparer.Ordinal);

		private static readonly Dictionary<KeyCode, string> JoystickButtonNameCache = new Dictionary<KeyCode, string>();

		private static float _lastMessageTime = -100f;

		private static bool _isDragonDelegateSearched;

		private static Func<Sadle, bool>? _isDragonDelegate;

		private static MethodInfo? _isDragonMethod;

		private static readonly object[] IsDragonArgs = new object[1];

		private static string _cachedDefaultRestrictedBiomeText = string.Empty;

		private static IReadOnlyList<string> _cachedDefaultRestrictedBiomes = Array.Empty<string>();

		internal static MethodBase? GetBetterRidingSetControlsPrefix()
		{
			return GetMethod("BetterRiding.Behaviour.FlightControls+Ygg_PlayerSetControls", "Prefix");
		}

		internal static MethodBase? GetBetterRidingPlayerUpdatePostfix()
		{
			return GetMethod("BetterRiding.Behaviour.MountController+Player_Update_Patch", "Postfix");
		}

		internal static void Shutdown()
		{
			PlayerStates.Clear();
			ResolvedBiomeNames.Clear();
			TypeCache.Clear();
			MethodCache.Clear();
			FieldCache.Clear();
			FlightKeyConfigCache.Clear();
			JoystickButtonNameCache.Clear();
			_lastMessageTime = -100f;
			_isDragonDelegateSearched = false;
			_isDragonDelegate = null;
			_isDragonMethod = null;
			IsDragonArgs[0] = null;
			_cachedDefaultRestrictedBiomeText = string.Empty;
			_cachedDefaultRestrictedBiomes = Array.Empty<string>();
		}

		internal static bool BlockFlightToggleIfRestricted(Player player, ref bool jump)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (jump || !IsFlightToggleKeyDown())
			{
				retu