Decompiled source of HiccupsQOLFixes v1.2.1

BepInEx/plugins/HiccupsQOLFixes/HiccupsQOLFixes.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HiccupsQOLFixes.Features;
using I2.Loc;
using Microsoft.CodeAnalysis;
using Mirror;
using PSS;
using QFSW.QC;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using Wish;
using ZeroFormatter;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HiccupsQOLFixes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1")]
[assembly: AssemblyProduct("HiccupsQOLFixes")]
[assembly: AssemblyTitle("HiccupsQOLFixes")]
[assembly: AssemblyVersion("1.2.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HiccupsQOLFixes
{
	[BepInPlugin("com.hiccups.sunhaven.qolfixes", "HiccupsQOLFixes", "1.2.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			RuntimeServices.Install(((BaseUnityPlugin)this).Logger);
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Fruit Tree Storage", "Enabled", true, "Let fruit trees accumulate up to 99 fruit and show a native item bubble above three. Enable on every multiplayer participant. Restart after changing this setting.").Value)
			{
				FruitTreeStorage.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Chest Hover Names", "Enabled", true, "Show a chest's native name when hovering its visible graphics at any distance. Does not extend interaction range. Restart after changing this setting.").Value)
			{
				ChestHoverName.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Safe Sleep at Home", "Enabled", true, "At midnight inside a player home, start normal sleep without a bed or pass-out penalties. Enable on each player who wants this behavior. Restart after changing this setting.").Value)
			{
				SafeSleepAtHome.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Dialogue Escape", "Enabled", true, "Use Escape to select an available native exit response. Required dialogue keeps normal pause behavior. Restart after changing this setting.").Value)
			{
				DialogueEscape.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Crafting Browser", "Enabled", true, "Add fuzzy and ingredient search, favorites, recent recipes, and live craftable filtering to station recipe lists. Restart after changing this setting.").Value)
			{
				CraftingBrowser.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Crafting Locations", "Enabled", true, "Show crafting stations in item tooltips. Restart after changing this setting.").Value)
			{
				CraftingLocations.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Save Backups", "Enabled", true, "Keep five verified backups per character after successful saves. Stored locally under the game's save-data folder. Restart after changing this setting.").Value)
			{
				SaveBackups.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Chest Crafting Exclusion", "Enabled", true, "Show the chest toggle and exclude selected chests from crafting stations. Restart the game after changing this setting.").Value)
			{
				ChestCraftingExclusion.Install(new Harmony("com.hiccups.sunhaven.qolfixes.chestcrafting"));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Chest Crafting Exclusion enabled");
			}
			ConfigEntry<bool> obj = ((BaseUnityPlugin)this).Config.Bind<bool>("Museum Donation", "Enabled", true, "Add Donate All Eligible to Covington's museum dialogue. Enable on every multiplayer participant. Restart after changing this setting.");
			ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Museum Tooltip", "Enabled", true, "Show museum donation status in item tooltips. Restart after changing this setting.");
			if (obj.Value || val.Value)
			{
				MuseumCatalog.Instance = new MuseumCatalog();
			}
			if (val.Value)
			{
				MuseumTooltip.Install(((BaseUnityPlugin)this).Logger);
			}
			if (((BaseUnityPlugin)this).Config.Bind<bool>("Crafting Station Settings", "Enabled", true, "Save and synchronize each station's chest, material, and sort toggles. Enable on every player. Restart after changing this setting.").Value)
			{
				CraftingStationSettings.Install();
			}
			if (obj.Value)
			{
				MuseumDonation.Install(((BaseUnityPlugin)this).Logger);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Museum Donation enabled");
			}
		}
	}
}
namespace HiccupsQOLFixes.Features
{
	internal static class ChestCraftingExclusion
	{
		internal const string Marker = "\u2063\u2063\u2063";

		private const string ButtonName = "ChestCraftingExclusionButton";

		private static readonly FieldInfo DataField = AccessTools.Field(typeof(Chest), "data");

		private static readonly FieldInfo UiField = AccessTools.Field(typeof(Chest), "ui");

		private static readonly FieldInfo NameField = AccessTools.Field(typeof(Chest), "chestName");

		internal static void Install(Harmony harmony)
		{
			harmony.PatchAll(typeof(CraftingInventoriesPatch));
			harmony.PatchAll(typeof(ChestInteractPatch));
			harmony.PatchAll(typeof(ChestNamePatch));
			harmony.PatchAll(typeof(ChestInteractionTextPatch));
			harmony.PatchAll(typeof(ChestMetaPatch));
		}

		internal static ChestData GetData(Chest chest)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return (ChestData)DataField.GetValue(chest);
		}

		internal static SunHavenInputField GetNameInput(Chest chest)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			return (SunHavenInputField)NameField.GetValue(chest);
		}

		internal static bool IsExcluded(Chest chest)
		{
			ChestData data = GetData(chest);
			return ((data != null) ? data.name : null)?.EndsWith("\u2063\u2063\u2063", StringComparison.Ordinal) ?? false;
		}

		internal static string Clean(string name)
		{
			return name?.Replace("\u2063\u2063\u2063", string.Empty);
		}

		internal static void EnsureButton(Chest chest)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (chest is HungryMonster)
			{
				return;
			}
			GameObject val = (GameObject)UiField.GetValue(chest);
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy || GetData(chest) == null)
			{
				return;
			}
			if ((Object)(object)((IEnumerable<Transform>)val.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform child) => ((Object)child).name == "ChestCraftingExclusionButton")) != (Object)null)
			{
				UpdateButton(chest);
				return;
			}
			NativeUiAssets.WithCraftingUI(delegate(CraftingUI template)
			{
				CreateToggle(chest, template);
			});
		}

		private static void CreateToggle(Chest chest, CraftingUI template)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: 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_016e: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: 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_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)chest == (Object)null || (Object)(object)template == (Object)null)
			{
				return;
			}
			GameObject val = (GameObject)UiField.GetValue(chest);
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy || val.GetComponentsInChildren<Transform>(true).Any((Transform child) => ((Object)child).name == "ChestCraftingExclusionButton"))
			{
				return;
			}
			Button val2 = ((IEnumerable<Button>)val.GetComponentsInChildren<Button>(true)).FirstOrDefault((Func<Button, bool>)((Button button) => Enumerable.Range(0, ((UnityEventBase)button.onClick).GetPersistentEventCount()).Any((int index) => ((UnityEventBase)button.onClick).GetPersistentTarget(index) == (Object)(object)chest.sellingInventory && ((UnityEventBase)button.onClick).GetPersistentMethodName(index) == "Sort")));
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Toggle sortUseNearbyChests = template.sortUseNearbyChests;
			Graphic targetGraphic = ((Selectable)sortUseNearbyChests).targetGraphic;
			Image val3 = (Image)(object)((targetGraphic is Image) ? targetGraphic : null);
			Graphic graphic = sortUseNearbyChests.graphic;
			Image val4 = (Image)(object)((graphic is Image) ? graphic : null);
			TextMeshProUGUI componentInChildren = ((Component)sortUseNearbyChests).GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)componentInChildren == (Object)null)
			{
				return;
			}
			GameObject val5 = new GameObject("ChestCraftingExclusionButton", new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Toggle),
				typeof(NavigationElement)
			});
			val5.transform.SetParent(((Component)val2).transform.parent, false);
			((Graphic)val5.GetComponent<Image>()).color = Color.clear;
			RectTransform val6 = (RectTransform)val5.transform;
			RectTransform val7 = (RectTransform)((Component)val2).transform;
			val6.anchorMin = val7.anchorMin;
			val6.anchorMax = val7.anchorMax;
			val6.pivot = new Vector2(0f, 0.5f);
			val6.sizeDelta = new Vector2(170f, val7.sizeDelta.y);
			val6.anchoredPosition = val7.anchoredPosition + new Vector2(val7.sizeDelta.x / 2f + 8f, 0f);
			Image val8 = NativeUiAssets.Image(val5.transform, "Background", val3);
			RectTransform rectTransform = ((Graphic)val8).rectTransform;
			RectTransform rectTransform2 = ((Graphic)val8).rectTransform;
			Vector2 val9 = default(Vector2);
			((Vector2)(ref val9))..ctor(0f, 0.5f);
			rectTransform2.anchorMax = val9;
			rectTransform.anchorMin = val9;
			((Graphic)val8).rectTransform.sizeDelta = new Vector2(12f, 12f);
			((Graphic)val8).rectTransform.anchoredPosition = new Vector2(6f, 0f);
			Image val10 = NativeUiAssets.Image(((Component)val8).transform, "Checkmark", val4);
			((Graphic)val10).rectTransform.anchorMin = Vector2.zero;
			((Graphic)val10).rectTransform.anchorMax = Vector2.one;
			val9 = (((Graphic)val10).rectTransform.offsetMin = (((Graphic)val10).rectTransform.offsetMax = Vector2.zero));
			TextMeshProUGUI component = new GameObject("Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			}).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).transform.SetParent(val5.transform, false);
			((TMP_Text)component).font = ((TMP_Text)componentInChildren).font;
			((TMP_Text)component).fontSharedMaterial = ((TMP_Text)componentInChildren).fontSharedMaterial;
			((TMP_Text)component).fontSize = ((TMP_Text)componentInChildren).fontSize;
			((Graphic)component).color = ((Graphic)componentInChildren).color;
			((TMP_Text)component).text = "Use for crafting";
			((TMP_Text)component).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)component).enableWordWrapping = false;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).rectTransform.anchorMin = Vector2.zero;
			((TMP_Text)component).rectTransform.anchorMax = Vector2.one;
			((TMP_Text)component).rectTransform.offsetMin = new Vector2(18f, 0f);
			((TMP_Text)component).rectTransform.offsetMax = Vector2.zero;
			Toggle component2 = val5.GetComponent<Toggle>();
			((Selectable)component2).targetGraphic = (Graphic)(object)val8;
			component2.graphic = (Graphic)(object)val10;
			((Selectable)component2).transition = ((Selectable)sortUseNearbyChests).transition;
			((Selectable)component2).colors = ((Selectable)sortUseNearbyChests).colors;
			component2.SetIsOnWithoutNotify(!IsExcluded(chest));
			((UnityEvent<bool>)(object)component2.onValueChanged).AddListener((UnityAction<bool>)delegate(bool included)
			{
				ChestData data = GetData(chest);
				if (data != null)
				{
					data.name = Clean(data.name) ?? "";
					if (!included)
					{
						data.name += "\u2063\u2063\u2063";
					}
					chest.SetChestName(data.name);
					chest.UpdateChestForMultiplayer();
					UpdateButton(chest);
				}
			});
		}

		internal static void UpdateButton(Chest chest)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			GameObject val = (GameObject)UiField.GetValue(chest);
			if (!((Object)(object)val == (Object)null))
			{
				Toggle val2 = ((IEnumerable<Toggle>)val.GetComponentsInChildren<Toggle>(true)).FirstOrDefault((Func<Toggle, bool>)((Toggle control) => ((Object)control).name == "ChestCraftingExclusionButton"));
				if ((Object)(object)val2 != (Object)null)
				{
					val2.SetIsOnWithoutNotify(!IsExcluded(chest));
				}
			}
		}
	}
	[HarmonyPatch(typeof(CraftingTable), "get_allInventories")]
	internal static class CraftingInventoriesPatch
	{
		private static void Postfix(ref List<Inventory> __result)
		{
			__result.RemoveAll((Inventory inventory) => ChestManager.associatedChests.TryGetValue(inventory, out var value) && ChestCraftingExclusion.IsExcluded(value));
		}
	}
	[HarmonyPatch(typeof(Chest), "Interact")]
	internal static class ChestInteractPatch
	{
		private static void Postfix(Chest __instance, int interactType)
		{
			if (interactType == 0)
			{
				ChestCraftingExclusion.EnsureButton(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Chest), "SetChestName")]
	internal static class ChestNamePatch
	{
		private static void Prefix(Chest __instance, ref string newName)
		{
			if (ChestCraftingExclusion.IsExcluded(__instance))
			{
				newName = ChestCraftingExclusion.Clean(newName) + "\u2063\u2063\u2063";
			}
		}

		private static void Postfix(Chest __instance)
		{
			SunHavenInputField nameInput = ChestCraftingExclusion.GetNameInput(__instance);
			if ((Object)(object)nameInput != (Object)null)
			{
				ChestData data = ChestCraftingExclusion.GetData(__instance);
				nameInput.SetTextWithoutNotify(ChestCraftingExclusion.Clean((data != null) ? data.name : null));
			}
		}
	}
	[HarmonyPatch(typeof(Chest), "get_InteractionPoint")]
	internal static class ChestInteractionTextPatch
	{
		private static void Postfix(InteractionInfo __result, string ___interactTextKey, string ___interactText)
		{
			if (__result?.interactionText != null)
			{
				for (int i = 0; i < __result.interactionText.Count; i++)
				{
					string text = ChestCraftingExclusion.Clean(__result.interactionText[i]);
					__result.interactionText[i] = (string.IsNullOrWhiteSpace(text) ? LocalizeText.TranslateText(___interactTextKey, ___interactText) : text);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Chest), "ReceiveNewMeta")]
	internal static class ChestMetaPatch
	{
		private static void Postfix(Chest __instance)
		{
			ChestCraftingExclusion.UpdateButton(__instance);
		}
	}
	internal static class ChestHoverName
	{
		private static readonly FieldInfo[] Glyphs = new FieldInfo[4]
		{
			AccessTools.Field(typeof(WorldInteraction), "interactionImage"),
			AccessTools.Field(typeof(WorldInteraction), "interaction2Image"),
			AccessTools.Field(typeof(WorldInteraction), "controllerInteractionImage"),
			AccessTools.Field(typeof(WorldInteraction), "controllerInteraction2Image")
		};

		private static WorldInteraction preview;

		private static string shownName;

		internal static void Install(ManualLogSource logger)
		{
			//IL_0005: 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_003e: Expected O, but got Unknown
			new Harmony("com.hiccups.sunhaven.qolfixes.chesthover").Patch((MethodBase)AccessTools.Method(typeof(PlayerInteractions), "LateUpdate", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ChestHoverName), "AfterInteractions", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			logger.LogInfo((object)"Chest hover names enabled");
		}

		private static void Hide()
		{
			if (Object.op_Implicit((Object)(object)preview))
			{
				((Component)preview).gameObject.SetActive(false);
			}
		}

		private static void AfterInteractions(PlayerInteractions __instance, WorldInteraction ___worldInteraction, Interaction ___currentTarget)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			Player instance = Player.Instance;
			if ((Object)(object)((Component)__instance).GetComponentInParent<Player>() != (Object)(object)instance)
			{
				return;
			}
			GameManager instance2 = SingletonBehaviour<GameManager>.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance2) || !Object.op_Implicit((Object)(object)instance.Camera) || MouseVisualManager.UsingController || GameManager.SceneTransitioning || UIHandler.InventoryOpen || UIHandler.UIWasOpenThisFrame || Cutscene.Active || !PlayerInput.AllowInput || (Object.op_Implicit((Object)(object)DialogueController.Instance) && DialogueController.Instance.DialogueOnGoing) || (Object.op_Implicit((Object)(object)EventSystem.current) && EventSystem.current.IsPointerOverGameObject()))
			{
				Hide();
				return;
			}
			Ray val = instance.Camera.ScreenPointToRay(MouseVisualManager.mousePosition);
			Chest val2 = null;
			float num = float.PositiveInfinity;
			float num2 = default(float);
			foreach (Decoration value2 in instance2.objects.Values)
			{
				Chest val3 = (Chest)(object)((value2 is Chest) ? value2 : null);
				if (!Object.op_Implicit((Object)(object)val3) || val3 is HungryMonster || !((Component)val3).gameObject.activeInHierarchy)
				{
					continue;
				}
				Renderer renderer = ((Entity)val3).Renderer;
				if (Object.op_Implicit((Object)(object)renderer) && renderer.enabled && ((Component)renderer).gameObject.activeInHierarchy)
				{
					Bounds bounds = renderer.bounds;
					if (((Bounds)(ref bounds)).IntersectRay(val, ref num2) && num2 >= 0f && num2 < num)
					{
						val2 = val3;
						num = num2;
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)val2) || (Object.op_Implicit((Object)(object)___worldInteraction) && ((Component)___worldInteraction).gameObject.activeInHierarchy && (Object)/*isinst with value type is only supported in some contexts*/ == (Object)(object)val2))
			{
				Hide();
				return;
			}
			InteractionInfo interactionPoint = val2.InteractionPoint;
			string text = ((interactionPoint.interactionText != null && interactionPoint.interactionText.Count > 0) ? ChestCraftingExclusion.Clean(interactionPoint.interactionText[0]) : null);
			if (string.IsNullOrWhiteSpace(text))
			{
				Hide();
				return;
			}
			if (!Object.op_Implicit((Object)(object)preview))
			{
				Prefabs instance3 = SingletonBehaviour<Prefabs>.Instance;
				if (!Object.op_Implicit((Object)(object)instance3) || !Object.op_Implicit((Object)(object)instance3.interaction))
				{
					return;
				}
				preview = Object.Instantiate<WorldInteraction>(instance3.interaction);
				((Object)preview).name = "HiccupsChestNamePreview";
				CanvasGroup[] componentsInChildren = ((Component)preview).GetComponentsInChildren<CanvasGroup>(true);
				foreach (CanvasGroup obj in componentsInChildren)
				{
					obj.alpha = 1f;
					obj.interactable = false;
					obj.blocksRaycasts = false;
				}
				shownName = null;
			}
			((Component)preview).gameObject.SetActive(true);
			preview.interactionObject.SetActive(true);
			((Component)preview).transform.position = interactionPoint.interactionPoint + new Vector3(0.125f, -11.05f, -11.05f);
			if (!(shownName != text))
			{
				return;
			}
			preview.SetInteractionText(new List<string> { text });
			FieldInfo[] glyphs = Glyphs;
			for (int i = 0; i < glyphs.Length; i++)
			{
				object? value = glyphs[i].GetValue(preview);
				Transform val4 = (Transform)((value is Transform) ? value : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					((Component)val4).gameObject.SetActive(false);
				}
			}
			Graphic[] componentsInChildren2 = ((Component)preview).GetComponentsInChildren<Graphic>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].raycastTarget = false;
			}
			shownName = text;
		}
	}
	internal sealed class CraftingBrowser : MonoBehaviour
	{
		private static readonly FieldInfo UIField = AccessTools.Field(typeof(CraftingTable), "craftingUI");

		private static readonly FieldInfo RecipesField = AccessTools.Field(typeof(CraftingTable), "_craftingRecipes");

		private static readonly FieldInfo OriginalField = AccessTools.Field(typeof(CraftingTable), "_saveCraftingRecipes");

		private static readonly FieldInfo FilterField = AccessTools.Field(typeof(CraftingTable), "filter");

		private static readonly FieldInfo TabField = AccessTools.Field(typeof(CraftingTable), "tabFilter");

		private static readonly FieldInfo MatsField = AccessTools.Field(typeof(CraftingTable), "hasMats");

		private static readonly FieldInfo PanelPrefab = AccessTools.Field(typeof(CraftingTable), "_craftingPanelPrefab");

		private static readonly FieldInfo PanelsField = AccessTools.Field(typeof(CraftingTable), "craftingPanels");

		private static ManualLogSource log;

		private CraftingTable table;

		private CraftingUI ui;

		private string query = "";

		private int mode;

		private float rebuildAt = -1f;

		private float checkAt;

		private int craftableHash;

		private bool hashReady;

		private TextMeshProUGUI status;

		private readonly List<TextMeshProUGUI> modeLabels = new List<TextMeshProUGUI>();

		internal static void Install(ManualLogSource logger)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_004d: 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)
			//IL_0082: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_016d: Expected O, but got Unknown
			log = logger;
			Harmony val = new Harmony("com.hiccups.sunhaven.qolfixes.craftingbrowser");
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "OpenUI", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingBrowser), "Opened", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "Filter", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingBrowser), "Search", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "InitializeCraftingPanelsRoutine", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingBrowser), "RecipeRoutine", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "Refresh", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingBrowser), "Refreshed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingPanel), "Initialize", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingBrowser), "PanelInitialized", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "Craft", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingBrowser), "BeforeCraft", (Type[])null), new HarmonyMethod(typeof(CraftingBrowser), "AfterCraft", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			log.LogInfo((object)"Crafting Browser enabled");
		}

		private static CraftingBrowser Get(CraftingTable table)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			CraftingBrowser craftingBrowser = ((Component)table).GetComponent<CraftingBrowser>();
			if ((Object)(object)craftingBrowser == (Object)null)
			{
				craftingBrowser = ((Component)table).gameObject.AddComponent<CraftingBrowser>();
				craftingBrowser.table = table;
				craftingBrowser.ui = (CraftingUI)UIField.GetValue(table);
			}
			return craftingBrowser;
		}

		private static void Opened(CraftingTable __instance)
		{
			CraftingBrowser craftingBrowser = Get(__instance);
			craftingBrowser.query = craftingBrowser.ui.sortByInput.text ?? "";
			craftingBrowser.BuildToolbar();
			craftingBrowser.Schedule();
			CraftingLocations.Register(((Decoration)__instance).id, (List<Recipe>)OriginalField.GetValue(__instance));
		}

		private static bool Search(CraftingTable __instance, string filterBy)
		{
			CraftingBrowser craftingBrowser = Get(__instance);
			craftingBrowser.query = (filterBy ?? "").Trim();
			if (craftingBrowser.query.Length > 120)
			{
				craftingBrowser.query = craftingBrowser.query.Substring(0, 120);
			}
			craftingBrowser.Schedule();
			return false;
		}

		private void Schedule()
		{
			rebuildAt = Time.unscaledTime + 0.15f;
		}

		private void Update()
		{
			if ((Object)(object)ui == (Object)null || !((Component)ui.craftingPane).gameObject.activeInHierarchy)
			{
				return;
			}
			if (rebuildAt >= 0f && Time.unscaledTime >= rebuildAt)
			{
				rebuildAt = -1f;
				table.Initialize(false);
			}
			if (Time.unscaledTime < checkAt || !(bool)MatsField.GetValue(table))
			{
				return;
			}
			checkAt = Time.unscaledTime + 1f;
			List<Recipe> obj = (List<Recipe>)OriginalField.GetValue(table);
			int num = 17;
			foreach (Recipe item in obj)
			{
				if ((Object)(object)item != (Object)null)
				{
					num = num * 31 + (table.CanCraft(item, 1) ? 1 : 0);
				}
			}
			if (hashReady && num != craftableHash)
			{
				Schedule();
			}
			craftableHash = num;
			hashReady = true;
		}

		private static void Refreshed(CraftingTable __instance)
		{
			CraftingBrowser component = ((Component)__instance).GetComponent<CraftingBrowser>();
			if ((Object)(object)component != (Object)null && (bool)MatsField.GetValue(__instance))
			{
				component.Schedule();
			}
		}

		private static void RecipeRoutine(CraftingTable __instance, ref IEnumerator __result)
		{
			__result = Get(__instance).FilterRoutine(__result);
		}

		private IEnumerator FilterRoutine(IEnumerator original)
		{
			rebuildAt = -1f;
			string selectedQuery = query;
			var source = from recipe in ((List<Recipe>)RecipesField.GetValue(table)).Where((Recipe recipe) => (Object)(object)recipe != (Object)null).ToList()
				select new
				{
					Recipe = recipe,
					Score = RecipeSearch.Score(selectedQuery, CraftingLocations.ItemName(((SerializedItemData)recipe.output2).id, recipe.output2.name), recipe.Input.Select((SerializedItemDataNamedAmount input) => CraftingLocations.ItemName(((SerializedItemData)input).id, input.name))),
					Recent = CraftingPreferences.RecentIndex(recipe)
				} into entry
				where entry.Score >= 0 && (mode != 1 || CraftingPreferences.Favorite(entry.Recipe)) && (mode != 2 || entry.Recent >= 0)
				select entry;
			if (mode == 2)
			{
				source = from entry in source
					orderby entry.Recent, entry.Score
					select entry;
			}
			else if (!string.IsNullOrWhiteSpace(selectedQuery))
			{
				source = source.OrderBy(entry => entry.Score);
			}
			List<Recipe> filtered = source.Select(entry => entry.Recipe).ToList();
			if ((Object)(object)status != (Object)null)
			{
				((TMP_Text)status).text = "Finding recipes...";
			}
			try
			{
				while (true)
				{
					object value = RecipesField.GetValue(table);
					object value2 = FilterField.GetValue(table);
					object value3 = TabField.GetValue(table);
					bool flag;
					try
					{
						RecipesField.SetValue(table, filtered);
						FilterField.SetValue(table, "");
						if (!string.IsNullOrWhiteSpace(selectedQuery))
						{
							TabField.SetValue(table, "");
						}
						flag = original.MoveNext();
					}
					finally
					{
						RecipesField.SetValue(table, value);
						FilterField.SetValue(table, value2);
						TabField.SetValue(table, value3);
					}
					if (!flag)
					{
						break;
					}
					yield return original.Current;
				}
				int count = ((Dictionary<Recipe, CraftingPanel>)PanelsField.GetValue(table)).Count;
				if ((Object)(object)status != (Object)null)
				{
					((TMP_Text)status).text = ((count == 0) ? "No matching recipes. Try All or clear a filter." : (count + " recipes | Search names or uses iron bar"));
				}
			}
			finally
			{
				(original as IDisposable)?.Dispose();
			}
		}

		private static void BeforeCraft(CraftingTable __instance, Recipe recipe, int amount, out bool __state)
		{
			__state = amount > 0 && __instance.CanCraft(recipe, amount);
		}

		private static void AfterCraft(CraftingTable __instance, Recipe recipe, bool __state)
		{
			if (__state)
			{
				CraftingPreferences.Record(recipe);
				CraftingBrowser component = ((Component)__instance).GetComponent<CraftingBrowser>();
				if ((Object)(object)component != (Object)null && (component.mode == 2 || (bool)MatsField.GetValue(__instance)))
				{
					component.Schedule();
				}
			}
		}

		private void BuildToolbar()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00b4: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)status != (Object)null)
			{
				return;
			}
			ScrollRect componentInParent = ((Component)ui.craftingPane).GetComponentInParent<ScrollRect>();
			if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent.viewport == (Object)null)
			{
				log.LogWarning((object)("Crafting browser could not find the recipe viewport for station " + ((Decoration)table).id));
				return;
			}
			CraftingPanel val = (CraftingPanel)PanelPrefab.GetValue(table);
			RectTransform component = new GameObject("HiccupsRecipeBrowser", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			RectTransform val2 = (RectTransform)((Component)componentInParent).transform;
			((Transform)component).SetParent(((Transform)val2).parent, false);
			component.anchorMin = new Vector2(val2.anchorMin.x, val2.anchorMax.y);
			component.anchorMax = val2.anchorMax;
			component.pivot = new Vector2(0.5f, 1f);
			component.sizeDelta = new Vector2(val2.sizeDelta.x, 38f);
			component.anchoredPosition = new Vector2(val2.anchoredPosition.x, val2.offsetMax.y);
			val2.offsetMax -= new Vector2(0f, 40f);
			string[] array = new string[3] { "All", "Favorites", "Recent" };
			for (int i = 0; i < array.Length; i++)
			{
				int index = i;
				TextMeshProUGUI label;
				Button obj = NativeButton((Transform)(object)component, val.buyButton, val.buyButtonTMP, array[i], out label);
				RectTransform val3 = (RectTransform)((Component)obj).transform;
				val3.anchorMin = new Vector2((float)i / 3f, 1f);
				val3.anchorMax = new Vector2((float)(i + 1) / 3f, 1f);
				val3.pivot = new Vector2(0.5f, 1f);
				val3.sizeDelta = new Vector2(-4f, 22f);
				val3.anchoredPosition = Vector2.zero;
				modeLabels.Add(label);
				((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
				{
					mode = index;
					UpdateModeLabels();
					Schedule();
				});
			}
			status = NativeLabel((Transform)(object)component, val.buyButtonTMP, "Search names or uses iron bar");
			((TMP_Text)status).fontSize = 9f;
			((TMP_Text)status).rectTransform.anchorMin = new Vector2(0f, 0f);
			((TMP_Text)status).rectTransform.anchorMax = new Vector2(1f, 0f);
			((TMP_Text)status).rectTransform.sizeDelta = new Vector2(0f, 14f);
			((TMP_Text)status).rectTransform.anchoredPosition = new Vector2(0f, 7f);
			Graphic placeholder = ui.sortByInput.placeholder;
			TMP_Text val4 = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
			if (val4 != null)
			{
				val4.text = "Search / uses ...";
			}
			TextMeshProUGUI[] componentsInChildren = ((Component)ui.sortHasMats).GetComponentsInChildren<TextMeshProUGUI>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				((TMP_Text)componentsInChildren[num]).text = "Craftable only";
			}
			UpdateModeLabels();
		}

		private void UpdateModeLabels()
		{
			string[] array = new string[3] { "All", "Favorites", "Recent" };
			for (int i = 0; i < modeLabels.Count; i++)
			{
				((TMP_Text)modeLabels[i]).text = ((i == mode) ? ("<color=#FEE463><b>" + array[i] + "</b></color>") : array[i]);
			}
		}

		private static void PanelInitialized(CraftingPanel __instance, CraftingTable craftingTable, Recipe recipe)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0081: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_009a: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			RecipeFavoriteControl recipeFavoriteControl = ((Component)__instance).GetComponent<RecipeFavoriteControl>();
			if ((Object)(object)recipeFavoriteControl == (Object)null)
			{
				recipeFavoriteControl = ((Component)__instance).gameObject.AddComponent<RecipeFavoriteControl>();
				GameObject val = new GameObject("FavoriteHeart", new Type[4]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(Button),
					typeof(NavigationElement)
				});
				val.transform.SetParent(((Component)__instance.outputImage).transform, false);
				RectTransform val2 = (RectTransform)val.transform;
				Vector2 anchorMin = (val2.anchorMax = Vector2.one);
				val2.anchorMin = anchorMin;
				val2.pivot = Vector2.one;
				val2.sizeDelta = new Vector2(14f, 12f);
				val2.anchoredPosition = new Vector2(-1f, -1f);
				recipeFavoriteControl.Background = val.GetComponent<Image>();
				recipeFavoriteControl.Background.preserveAspect = true;
				Image component = new GameObject("FilledHeart", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				}).GetComponent<Image>();
				((Component)component).transform.SetParent(val.transform, false);
				((Graphic)component).rectTransform.anchorMin = Vector2.zero;
				((Graphic)component).rectTransform.anchorMax = Vector2.one;
				RectTransform rectTransform = ((Graphic)component).rectTransform;
				anchorMin = (((Graphic)component).rectTransform.offsetMax = Vector2.zero);
				rectTransform.offsetMin = anchorMin;
				component.preserveAspect = true;
				((Graphic)component).raycastTarget = false;
				recipeFavoriteControl.Fill = component;
				Button component2 = val.GetComponent<Button>();
				((Selectable)component2).targetGraphic = (Graphic)(object)recipeFavoriteControl.Background;
				((Selectable)component2).transition = (Transition)1;
				((UnityEvent)component2.onClick).AddListener(new UnityAction(recipeFavoriteControl.Toggle));
			}
			recipeFavoriteControl.Recipe = recipe;
			recipeFavoriteControl.Browser = Get(craftingTable);
			recipeFavoriteControl.Refresh();
		}

		internal void FavoriteChanged()
		{
			if (mode == 1)
			{
				Schedule();
			}
		}

		private static Button NativeButton(Transform parent, Button source, TextMeshProUGUI fontSource, string text, out TextMeshProUGUI label)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Hiccups" + text, new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button),
				typeof(NavigationElement)
			});
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			Graphic targetGraphic = ((Selectable)source).targetGraphic;
			Image val2 = (Image)(((object)((targetGraphic is Image) ? targetGraphic : null)) ?? ((object)((Component)source).GetComponent<Image>()));
			if ((Object)(object)val2 != (Object)null)
			{
				component.sprite = val2.sprite;
				component.type = val2.type;
				((Graphic)component).color = ((Graphic)val2).color;
				((Graphic)component).material = ((Graphic)val2).material;
				component.pixelsPerUnitMultiplier = val2.pixelsPerUnitMultiplier;
			}
			Button component2 = val.GetComponent<Button>();
			((Selectable)component2).targetGraphic = (Graphic)(object)component;
			((Selectable)component2).transition = (Transition)(((int)((Selectable)source).transition == 3) ? 1 : ((int)((Selectable)source).transition));
			((Selectable)component2).colors = ((Selectable)source).colors;
			((Selectable)component2).spriteState = ((Selectable)source).spriteState;
			label = NativeLabel(val.transform, fontSource, text);
			return component2;
		}

		private static TextMeshProUGUI NativeLabel(Transform parent, TextMeshProUGUI source, string text)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI component = new GameObject("Label", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			}).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).transform.SetParent(parent, false);
			((TMP_Text)component).font = ((TMP_Text)source).font;
			((TMP_Text)component).fontSharedMaterial = ((TMP_Text)source).fontSharedMaterial;
			((TMP_Text)component).fontSize = 14f;
			((Graphic)component).color = ((Graphic)source).color;
			((TMP_Text)component).alignment = (TextAlignmentOptions)514;
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).enableWordWrapping = false;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			((TMP_Text)component).text = text;
			((TMP_Text)component).rectTransform.anchorMin = Vector2.zero;
			((TMP_Text)component).rectTransform.anchorMax = Vector2.one;
			((TMP_Text)component).rectTransform.offsetMin = new Vector2(2f, 0f);
			((TMP_Text)component).rectTransform.offsetMax = new Vector2(-2f, 0f);
			return component;
		}
	}
	internal sealed class RecipeFavoriteControl : MonoBehaviour
	{
		internal Recipe Recipe;

		internal CraftingBrowser Browser;

		internal Image Background;

		internal Image Fill;

		internal void Refresh()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (NativeUiAssets.Hearts(out var empty, out var full, out var backgroundColor, out var fillColor))
			{
				Background.sprite = empty;
				((Graphic)Background).color = backgroundColor;
				Fill.sprite = full;
				((Graphic)Fill).color = fillColor;
			}
			((Behaviour)Background).enabled = (Object)(object)Background.sprite != (Object)null;
			((Behaviour)Fill).enabled = (Object)(object)Fill.sprite != (Object)null && CraftingPreferences.Favorite(Recipe);
		}

		internal void Toggle()
		{
			CraftingPreferences.Toggle(Recipe);
			Refresh();
			Browser.FavoriteChanged();
		}
	}
	internal static class CraftingLocations
	{
		private static readonly Dictionary<int, HashSet<int>> stations = new Dictionary<int, HashSet<int>>();

		private static readonly Dictionary<int, string> names = new Dictionary<int, string>();

		internal static void Install(ManualLogSource logger)
		{
			using (Stream stream = typeof(CraftingLocations).Assembly.GetManifestResourceStream("HiccupsQOLFixes.CraftingLocations"))
			{
				if (stream == null)
				{
					throw new InvalidOperationException("Crafting location index is missing.");
				}
				using StreamReader streamReader = new StreamReader(stream);
				string text;
				while ((text = streamReader.ReadLine()) != null)
				{
					string[] array = text.Split(new char[1] { ':' });
					if (array.Length == 2)
					{
						stations[int.Parse(array[0])] = new HashSet<int>(array[1].Split(new char[1] { ',' }).Select(int.Parse));
					}
				}
			}
			ItemTooltipExtensions.Add(logger, Description);
			logger.LogInfo((object)("Crafting location tooltips ready for " + stations.Count + " items."));
		}

		internal static void Register(int stationId, IEnumerable<Recipe> recipes)
		{
			if (stationId <= 0 || recipes == null)
			{
				return;
			}
			foreach (Recipe recipe in recipes)
			{
				if (!((Object)(object)recipe == (Object)null) && recipe.output2 != null)
				{
					if (!stations.TryGetValue(((SerializedItemData)recipe.output2).id, out var value))
					{
						value = (stations[((SerializedItemData)recipe.output2).id] = new HashSet<int>());
					}
					value.Add(stationId);
				}
			}
		}

		internal static string ItemName(int id, string fallback)
		{
			ItemInfoDatabase instance = SingletonBehaviour<ItemInfoDatabase>.Instance;
			string text;
			if (instance?.allItemSellInfos == null || !instance.allItemSellInfos.TryGetValue(id, out var value))
			{
				text = fallback;
				if (text == null)
				{
					return "";
				}
			}
			else
			{
				text = LocalizeText.TranslateText(value.keyName, value.name);
			}
			return text;
		}

		private static string Description(int id)
		{
			if (!stations.TryGetValue(id, out var value))
			{
				return "";
			}
			string value2;
			string[] array = (from name in (from station in ((IEnumerable<int>)value).Where((Func<int, bool>)Database.ValidID)
					select ItemName(station, names.TryGetValue(station, out value2) ? value2 : ("Station " + station)).Replace(" (Old)", "")).Distinct()
				orderby name
				select name).ToArray();
			if (array.Length == 0)
			{
				return "";
			}
			return "\n\n<line-height=100%><b>Crafted at:</b> " + string.Join(", ", array.Select((string name) => "<noparse>" + name + "</noparse>")) + "</line-height>";
		}
	}
	internal static class CraftingPreferences
	{
		[Serializable]
		private sealed class Preferences
		{
			public List<string> favorites = new List<string>();

			public List<string> recent = new List<string>();
		}

		private const string Progress = "HiccupsQOLFixes.CraftingPreferences";

		private static CharacterData character;

		private static Preferences current;

		private static Preferences Current
		{
			get
			{
				GameSave instance = SingletonBehaviour<GameSave>.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					GameSaveData currentSave = instance.CurrentSave;
					obj = ((currentSave != null) ? currentSave.characterData : null);
				}
				CharacterData val = (CharacterData)obj;
				if (current != null && val == character)
				{
					return current;
				}
				character = val;
				current = new Preferences();
				if (val == null)
				{
					return current;
				}
				string progressStringCharacter = instance.GetProgressStringCharacter("HiccupsQOLFixes.CraftingPreferences");
				if (!string.IsNullOrEmpty(progressStringCharacter))
				{
					try
					{
						current = JsonUtility.FromJson<Preferences>(Encoding.UTF8.GetString(Convert.FromBase64String(progressStringCharacter))) ?? current;
					}
					catch (Exception ex) when (ex is FormatException || ex is ArgumentException)
					{
					}
				}
				current.favorites = current.favorites ?? new List<string>();
				current.recent = (current.recent ?? new List<string>()).Distinct().Take(30).ToList();
				return current;
			}
		}

		internal static string Key(Recipe recipe)
		{
			return ((SerializedItemData)recipe.output2).id + "|" + ((Object)recipe).name;
		}

		internal static bool Favorite(Recipe recipe)
		{
			return Current.favorites.Contains(Key(recipe));
		}

		internal static int RecentIndex(Recipe recipe)
		{
			return Current.recent.IndexOf(Key(recipe));
		}

		internal static void Toggle(Recipe recipe)
		{
			Preferences preferences = Current;
			if (!preferences.favorites.Remove(Key(recipe)))
			{
				preferences.favorites.Add(Key(recipe));
			}
			Save();
		}

		internal static void Record(Recipe recipe)
		{
			Preferences preferences = Current;
			preferences.recent.Remove(Key(recipe));
			preferences.recent.Insert(0, Key(recipe));
			if (preferences.recent.Count > 30)
			{
				preferences.recent.RemoveRange(30, preferences.recent.Count - 30);
			}
			Save();
		}

		private static void Save()
		{
			if (character != null)
			{
				SingletonBehaviour<GameSave>.Instance.SetProgressStringCharacter("HiccupsQOLFixes.CraftingPreferences", Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonUtility.ToJson((object)current))));
			}
		}
	}
	internal static class CraftingStationSettings
	{
		[Serializable]
		private sealed class Settings
		{
			public int version = 1;

			public bool nearby = true;

			public bool materials;

			public int sort = 1;

			public bool direction = true;
		}

		private const string Prefix = "HiccupsQOLFixes.Station.";

		private static readonly FieldInfo Nearby = AccessTools.Field(typeof(CraftingTable), "useNearbyChests");

		private static readonly FieldInfo Materials = AccessTools.Field(typeof(CraftingTable), "hasMats");

		private static readonly FieldInfo UI = AccessTools.Field(typeof(CraftingTable), "craftingUI");

		private static readonly FieldInfo Recipes = AccessTools.Field(typeof(CraftingTable), "_craftingRecipes");

		private static readonly FieldInfo Original = AccessTools.Field(typeof(CraftingTable), "_saveCraftingRecipes");

		private static readonly FieldInfo Reversed = AccessTools.Field(typeof(CraftingTable), "_reversedSavedCraftingRecipes");

		private static readonly HashSet<CraftingTable> Open = new HashSet<CraftingTable>();

		private static bool applying;

		private static GameSave Save => SingletonBehaviour<GameSave>.Instance;

		internal static void Install()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_00fd: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			Harmony val = new Harmony("com.hiccups.sunhaven.qolfixes.stationsettings");
			string[] array = new string[5] { "ToggleUseNearbyChests", "ToggleHasMats", "TogglePriceSorting", "ToggleRaritySorting", "ResetSorting" };
			foreach (string text in array)
			{
				val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), text, (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingStationSettings), "Changed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "SetMeta", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingStationSettings), "Restore", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "OpenUI", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "Opening", (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "Opened", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "CloseUI", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "Closing", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(CraftingTable), "OnDisable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "Closing", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(GameSave), "SetProgressStringWorld", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CraftingStationSettings), "ProgressChanged", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(NetworkWorld), "UserCode_CmdSetProgressStringWorldRPC__String__String", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "ServerProgress", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(GameSave), "RemoveDecorationFromSave", (Type[])null, (Type[])null), new HarmonyMethod(typeof(CraftingStationSettings), "Removing", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static string Key(int scene, Vector3Int position, int id)
		{
			return "HiccupsQOLFixes.Station." + scene + "." + ((Vector3Int)(ref position)).x + "." + ((Vector3Int)(ref position)).y + "." + ((Vector3Int)(ref position)).z + "." + id;
		}

		private static string Key(CraftingTable table)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return Key(((Decoration)table).sceneID, ((Decoration)table).Position, ((Decoration)table).id);
		}

		private static Settings Read(CraftingTable table)
		{
			GameSave save = Save;
			if (((save != null) ? save.CurrentWorld : null) == null)
			{
				return new Settings();
			}
			string progressStringWorld = Save.GetProgressStringWorld(Key(table));
			if (string.IsNullOrEmpty(progressStringWorld))
			{
				return new Settings();
			}
			try
			{
				Settings settings = JsonUtility.FromJson<Settings>(progressStringWorld);
				return (settings != null && settings.version == 1 && (settings.sort == 1 || settings.sort == 2)) ? settings : new Settings();
			}
			catch (ArgumentException)
			{
				return new Settings();
			}
		}

		private static void Changed(CraftingTable __instance, MethodBase __originalMethod, object[] __args)
		{
			if (applying || !Open.Contains(__instance))
			{
				return;
			}
			GameSave save = Save;
			if (((save != null) ? save.CurrentWorld : null) != null)
			{
				Settings settings = Read(__instance);
				switch (__originalMethod.Name)
				{
				case "ToggleUseNearbyChests":
					settings.nearby = (bool)__args[0];
					break;
				case "ToggleHasMats":
					settings.materials = (bool)__args[0];
					break;
				case "TogglePriceSorting":
					settings.sort = 2;
					settings.direction = (bool)__args[0];
					break;
				case "ToggleRaritySorting":
					settings.sort = 1;
					settings.direction = (bool)__args[0];
					break;
				case "ResetSorting":
					settings.sort = 1;
					settings.direction = true;
					break;
				}
				Save.SetProgressStringWorld(Key(__instance), JsonUtility.ToJson((object)settings), true);
			}
		}

		private static void Opening(CraftingTable __instance)
		{
			Restore(__instance);
		}

		private static void Opened(CraftingTable __instance)
		{
			Open.Add(__instance);
			Apply(__instance, refresh: true);
		}

		private static void Closing(CraftingTable __instance)
		{
			Open.Remove(__instance);
		}

		private static void Restore(CraftingTable __instance)
		{
			Apply(__instance, refresh: false);
		}

		private static void Apply(CraftingTable table, bool refresh)
		{
			if ((Object)(object)table == (Object)null)
			{
				return;
			}
			GameSave save = Save;
			if (((save != null) ? save.CurrentWorld : null) == null)
			{
				return;
			}
			Settings settings = Read(table);
			bool flag = applying;
			applying = true;
			try
			{
				Nearby.SetValue(table, settings.nearby);
				Materials.SetValue(table, settings.materials);
				object? value = UI.GetValue(table);
				CraftingUI val = (CraftingUI)((value is CraftingUI) ? value : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				val.sortUseNearbyChests.SetIsOnWithoutNotify(settings.nearby);
				val.sortHasMats.SetIsOnWithoutNotify(settings.materials);
				val.sortLowToHighPriceToggle.SetIsOnWithoutNotify(settings.sort == 2 && !settings.direction);
				val.sortHighToLowPriceToggle.SetIsOnWithoutNotify(settings.sort == 2 && settings.direction);
				val.sortLowToHighRarityToggle.SetIsOnWithoutNotify(settings.sort == 1 && settings.direction);
				val.sortHighToLowRarityToggle.SetIsOnWithoutNotify(settings.sort == 1 && !settings.direction);
				if (!refresh || !(Original.GetValue(table) is List<Recipe> list))
				{
					return;
				}
				if (settings.sort == 1)
				{
					Recipes.SetValue(table, settings.direction ? list : Reversed.GetValue(table));
				}
				else
				{
					Func<Recipe, float> keySelector = (Recipe recipe) => SingletonBehaviour<ItemInfoDatabase>.Instance.allItemSellInfos[((SerializedItemData)recipe.output2).id].sellPrice * (float)recipe.output2.amount;
					Recipes.SetValue(table, (settings.direction ? list.OrderByDescending(keySelector) : list.OrderBy(keySelector)).ToList());
				}
				if (refresh)
				{
					table.Initialize(false);
				}
			}
			finally
			{
				applying = flag;
			}
		}

		private static void ProgressChanged(string progressID)
		{
			if (!progressID.StartsWith("HiccupsQOLFixes.Station.", StringComparison.Ordinal))
			{
				return;
			}
			CraftingTable[] array = Open.ToArray();
			foreach (CraftingTable val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					Open.Remove(val);
				}
				else if (Key(val) == progressID)
				{
					Apply(val, refresh: true);
				}
			}
		}

		private static void ServerProgress(string progress, string value)
		{
			if (progress.StartsWith("HiccupsQOLFixes.Station.", StringComparison.Ordinal))
			{
				GameSave save = Save;
				if (((save != null) ? save.CurrentWorld : null) != null)
				{
					Save.SetProgressStringWorld(progress, value, false);
				}
			}
		}

		private static void Removing(Vector3Int position, int sceneID)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GameSave save = Save;
			object obj;
			if (save == null)
			{
				obj = null;
			}
			else
			{
				WorldData currentWorld = save.CurrentWorld;
				obj = ((currentWorld != null) ? currentWorld.Decorations : null);
			}
			if (obj != null && Save.CurrentWorld.Decorations.TryGetValue((short)sceneID, out var value) && value.TryGetValue(new DecorationKey((ushort)((Vector3Int)(ref position)).x, (ushort)((Vector3Int)(ref position)).y, (sbyte)((Vector3Int)(ref position)).z), out var value2))
			{
				string text = Key(sceneID, position, value2.id);
				if (!string.IsNullOrEmpty(Save.GetProgressStringWorld(text)))
				{
					Save.SetProgressStringWorld(text, "", false);
				}
			}
		}
	}
	internal static class DialogueEscape
	{
		private static readonly Dictionary<MethodInfo, bool> safeActions = new Dictionary<MethodInfo, bool>();

		private static readonly FieldInfo Options = AccessTools.Field(typeof(DialogueController), "_options");

		private static readonly FieldInfo OptionIndex = AccessTools.Field(typeof(DialogueController), "_optionIndex");

		private static ManualLogSource log;

		internal static void Install(ManualLogSource logger)
		{
			//IL_000b: 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_0044: Expected O, but got Unknown
			log = logger;
			new Harmony("com.hiccups.sunhaven.qolfixes.dialogueescape").Patch((MethodBase)AccessTools.Method(typeof(UIHandler), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DialogueEscape), "BeforeUpdate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool BeforeUpdate(UIHandler __instance, bool ___uiOpen)
		{
			DialogueController instance = DialogueController.Instance;
			if (!Object.op_Implicit((Object)(object)instance) || !instance.DialogueOnGoing || instance.Scrolling || Cutscene.Active || !Object.op_Implicit((Object)(object)Player.Instance) || !PlayerInput.AllowInput || GameManager.SceneTransitioning || ___uiOpen || UIHandler.InventoryOpen || RewiredManager.KeybindsOpen || (Object.op_Implicit((Object)(object)QuantumConsole.Instance) && QuantumConsole.Instance.IsActive))
			{
				return true;
			}
			if (!PlayerInput.GetButtonDown((Button)40, true) && !PlayerInput.GetButtonDown((Button)9, true))
			{
				return true;
			}
			try
			{
				List<(TextMeshProUGUI, UnityAction, Image, string, bool)> options = (List<(TextMeshProUGUI, UnityAction, Image, string, bool)>)Options.GetValue(instance);
				string[] exitLabels = new string[5]
				{
					ScriptLocalization.SeeYa,
					ScriptLocalization.SeeYaExcited,
					ScriptLocalization.ActuallyNevermind00,
					ScriptLocalization.NoThanks,
					ScriptLocalization.NPC_Covington_O4
				};
				int[] array = (from index in Enumerable.Range(0, options.Count)
					where options[index].Item5 && Object.op_Implicit((Object)(object)options[index].Item1) && ((Component)options[index].Item1).gameObject.activeInHierarchy && IsExit(options[index].Item2)
					select index).ToArray();
				int num = array.Where((int index) => exitLabels.Any((string label) => string.Equals(label?.Trim(), options[index].Item4?.Trim(), StringComparison.Ordinal))).DefaultIfEmpty(-1).First();
				if (num < 0 && array.Length == 1 && options[array[0]].Item2 != null)
				{
					num = array[0];
				}
				if (num >= 0)
				{
					OptionIndex.SetValue(instance, num);
					instance.Continue();
					return false;
				}
			}
			catch (Exception ex)
			{
				log.LogError((object)ex);
			}
			return true;
		}

		private static bool IsExit(UnityAction action)
		{
			if (action == null)
			{
				return true;
			}
			if (((Delegate)(object)action).GetInvocationList().Length != 1)
			{
				return false;
			}
			if (!safeActions.TryGetValue(((Delegate)(object)action).Method, out var value))
			{
				value = (safeActions[((Delegate)(object)action).Method] = IsExitMethod(((Delegate)(object)action).Method));
			}
			if (!value)
			{
				return false;
			}
			object? target = ((Delegate)(object)action).Target;
			Object val = (Object)((target is Object) ? target : null);
			if (val != null && !Object.op_Implicit(val))
			{
				return false;
			}
			object? target2 = ((Delegate)(object)action).Target;
			LocalizedDialogueTree val2 = (LocalizedDialogueTree)((target2 is LocalizedDialogueTree) ? target2 : null);
			if (val2 == null && ((Delegate)(object)action).Target != null)
			{
				val2 = (from field in ((Delegate)(object)action).Target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where field.FieldType == typeof(LocalizedDialogueTree)
					select field).Select(delegate(FieldInfo field)
				{
					object? value2 = field.GetValue(((Delegate)(object)action).Target);
					return (LocalizedDialogueTree)((value2 is LocalizedDialogueTree) ? value2 : null);
				}).FirstOrDefault();
			}
			if (val2 != null)
			{
				return val2.OnEnd != null;
			}
			return true;
		}

		private static bool IsExitMethod(MethodInfo method)
		{
			if (method.Module != typeof(DialogueController).Module || method.GetMethodBody() == null)
			{
				return false;
			}
			byte[] iLAsByteArray = method.GetMethodBody().GetILAsByteArray();
			int num = 0;
			bool flag = false;
			int num2 = 0;
			while (num2 < iLAsByteArray.Length)
			{
				short num3 = iLAsByteArray[num2++];
				OpCode ldfld = OpCodes.Ldfld;
				if (num3 == ldfld.Value)
				{
					if (num2 + 4 > iLAsByteArray.Length)
					{
						return false;
					}
					FieldInfo fieldInfo = method.Module.ResolveField(BitConverter.ToInt32(iLAsByteArray, num2));
					num2 += 4;
					if (fieldInfo == null)
					{
						return false;
					}
					if (fieldInfo.DeclaringType == typeof(LocalizedDialogueTree) && fieldInfo.Name == "OnEnd")
					{
						flag = true;
					}
					else if (fieldInfo.Name != "<>4__this")
					{
						return false;
					}
					continue;
				}
				ldfld = OpCodes.Call;
				if (num3 != ldfld.Value)
				{
					ldfld = OpCodes.Callvirt;
					if (num3 != ldfld.Value)
					{
						ldfld = OpCodes.Brtrue_S;
						if (num3 != ldfld.Value)
						{
							ldfld = OpCodes.Brtrue;
							if (num3 != ldfld.Value)
							{
								ldfld = OpCodes.Nop;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Ldarg_0;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Ldc_I4_0;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Dup;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Pop;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Brtrue_S;
								if (num3 == ldfld.Value)
								{
									continue;
								}
								ldfld = OpCodes.Brtrue;
								if (num3 != ldfld.Value)
								{
									ldfld = OpCodes.Ret;
									if (num3 != ldfld.Value)
									{
										return false;
									}
								}
								continue;
							}
						}
						ldfld = OpCodes.Brtrue_S;
						int num4 = ((num3 == ldfld.Value) ? 1 : 4);
						if (num2 + num4 > iLAsByteArray.Length)
						{
							return false;
						}
						int num5 = ((num4 == 1) ? ((sbyte)iLAsByteArray[num2]) : BitConverter.ToInt32(iLAsByteArray, num2));
						num2 += num4;
						if (num5 < 0 || num2 + num5 >= iLAsByteArray.Length)
						{
							return false;
						}
						continue;
					}
				}
				if (num2 + 4 > iLAsByteArray.Length)
				{
					return false;
				}
				MethodInfo methodInfo = method.Module.ResolveMethod(BitConverter.ToInt32(iLAsByteArray, num2)) as MethodInfo;
				num2 += 4;
				if (methodInfo == null)
				{
					return false;
				}
				if (methodInfo.DeclaringType == typeof(UnityAction) && methodInfo.Name == "Invoke" && flag)
				{
					num++;
					continue;
				}
				if ((methodInfo.DeclaringType == typeof(NPC) || methodInfo.DeclaringType == typeof(NPCAI)) && methodInfo.Name == "EndInteract")
				{
					num++;
					continue;
				}
				return false;
			}
			return num == 1;
		}
	}
	internal static class DonationCodec
	{
		internal static string Encode(DonationPacket packet)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			DonationProtocol.Validate(packet);
			using MemoryStream memoryStream = new MemoryStream();
			((XmlObjectSerializer)new DataContractJsonSerializer(typeof(DonationPacket))).WriteObject((Stream)memoryStream, (object)packet);
			string text = Encoding.UTF8.GetString(memoryStream.ToArray());
			if (text.Length > 30000)
			{
				throw new InvalidOperationException("Museum donation message is too large.");
			}
			return text;
		}

		internal static DonationPacket Decode(string json, bool network = false)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(json) || json.Length > 30000)
			{
				throw new InvalidOperationException("Invalid museum donation message size.");
			}
			using MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
			DonationPacket donationPacket = (DonationPacket)((XmlObjectSerializer)new DataContractJsonSerializer(typeof(DonationPacket))).ReadObject((Stream)memoryStream);
			if (network && donationPacket != null && donationPacket.items == null && (donationPacket.operation == "prepare" || donationPacket.operation == "offer" || donationPacket.operation == "success"))
			{
				throw new InvalidOperationException("Museum donation message is missing its item list. Update the mod on every player.");
			}
			return DonationProtocol.Validate(donationPacket);
		}
	}
	[DataContract]
	internal sealed class DonationAmount
	{
		[DataMember]
		public int id;

		[DataMember]
		public int amount;
	}
	[DataContract]
	internal sealed class DonationPacket
	{
		[DataMember]
		public int version = 1;

		[DataMember]
		public string operation;

		[DataMember]
		public string transaction;

		[DataMember]
		public string world;

		[DataMember]
		public string error;

		[DataMember]
		public DonationAmount[] items;

		[DataMember]
		public string[] completed;

		[DataMember]
		public int collections;

		[DataMember]
		public string escrow;
	}
	internal static class DonationProtocol
	{
		internal static DonationPacket Validate(DonationPacket packet)
		{
			if (packet == null || packet.version != 1 || !Guid.TryParse(packet.transaction, out var _))
			{
				throw new InvalidOperationException("Incompatible museum donation message.");
			}
			switch (packet.operation)
			{
			default:
				throw new InvalidOperationException("Unknown museum donation operation.");
			case "prepare":
			case "success":
			case "offer":
			case "query":
			case "commit":
			case "rejected":
			case "otherworld":
				packet.items = packet.items ?? new DonationAmount[0];
				packet.completed = packet.completed ?? new string[0];
				if (packet.items.Length > 50 || packet.items.Any((DonationAmount item) => item == null || item.id <= 0 || item.amount <= 0) || packet.items.Select((DonationAmount item) => item.id).Distinct().Count() != packet.items.Length)
				{
					throw new InvalidOperationException("Invalid museum donation item list.");
				}
				return packet;
			}
		}
	}
	internal static class DonationRoutine
	{
		internal static IEnumerator Guard(IEnumerator routine, Action<Exception> failed)
		{
			try
			{
				while (true)
				{
					object current;
					try
					{
						if (!routine.MoveNext())
						{
							break;
						}
						current = routine.Current;
					}
					catch (Exception obj)
					{
						failed(obj);
						break;
					}
					yield return current;
				}
			}
			finally
			{
				(routine as IDisposable)?.Dispose();
			}
		}
	}
	internal static class FruitTreeStorage
	{
		private sealed class TreeState
		{
			public int extra;

			public bool loading;

			public CraftingNotificationBubble bubble;
		}

		private struct OvernightState
		{
			public int extra;

			public int occupied;
		}

		private const int Capacity = 99;

		private const int Marker = 827606600;

		private static ManualLogSource log;

		private static bool reportedVisualError;

		private static readonly ConditionalWeakTable<ForageTree, TreeState> States = new ConditionalWeakTable<ForageTree, TreeState>();

		private static readonly MethodInfo GetFruit = AccessTools.Method(typeof(ForageTree), "GetFruit", (Type[])null, (Type[])null);

		internal static void Install(ManualLogSource logger)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0059: Expected O, but got Unknown
			//IL_005a: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00a3: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_00ed: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_016d: Expected O, but got Unknown
			//IL_016e: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01b7: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Expected O, but got Unknown
			log = logger;
			Harmony val = new Harmony("com.hiccups.sunhaven.qolfixes.fruittrees");
			val.Patch((MethodBase)AccessTools.Method(typeof(DecorationUpdater), "FruitTree_UpdateMetaOvernight", (Type[])null, (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "BeforeGrowth", (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "AfterGrowth", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(ForageTree), "SetMeta", (Type[])null, (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "Loading", (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "Refresh", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(ForageTree), "ReceiveNewMeta", (Type[])null, (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "Receiving", (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "Refresh", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(ForageTree), "SaveMeta", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(FruitTreeStorage), "Saving", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(ForageTree), "Shake", (Type[])null, (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "BeforeShake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FruitTreeStorage), "AfterHarvest", (Type[])null), (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(ForageTree), "HandleWoodDrop", (Type[])null, (Type[])null), new HarmonyMethod(typeof(FruitTreeStorage), "BeforeChop", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FruitTreeStorage), "AfterHarvest", (Type[])null), (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.Method(typeof(NetworkGamePlayer), "UserCode_RpcShakeTree__Vector3Int__Int16__Byte[]", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(FruitTreeStorage), "ReceivedShake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			logger.LogInfo((object)"Fruit Tree Storage enabled (99 fruit per tree)");
		}

		private static int Count(ForageTreeSaveData data)
		{
			if (data != null)
			{
				return (data.spot1 ? 1 : 0) + (data.spot2 ? 1 : 0) + (data.spot3 ? 1 : 0);
			}
			return 0;
		}

		private static int ReadExtra(byte[] meta)
		{
			if (meta == null || meta.Length < 12)
			{
				return 0;
			}
			int num = BitConverter.ToInt32(meta, 0);
			if (num < 4 || num != meta.Length - 8 || BitConverter.ToInt32(meta, num) != 827606600)
			{
				return 0;
			}
			return Mathf.Clamp(BitConverter.ToInt32(meta, num + 4), 0, 96);
		}

		private static byte[] WithExtra(byte[] meta, int extra)
		{
			if (meta == null || meta.Length < 4)
			{
				return meta;
			}
			int num = BitConverter.ToInt32(meta, 0);
			if (num < 4 || num > meta.Length)
			{
				return meta;
			}
			byte[] array = new byte[num + ((extra > 0) ? 8 : 0)];
			Buffer.BlockCopy(meta, 0, array, 0, num);
			if (extra > 0)
			{
				Buffer.BlockCopy(BitConverter.GetBytes(827606600), 0, array, num, 4);
				Buffer.BlockCopy(BitConverter.GetBytes(Mathf.Clamp(extra, 0, 96)), 0, array, num + 4, 4);
			}
			return array;
		}

		private static void BeforeGrowth(ref DecorationPositionData decorationData, out OvernightState __state)
		{
			ForageTreeSaveData data = null;
			Decoration.DeserializeMeta<ForageTreeSaveData>(decorationData.meta, ref data);
			__state = new OvernightState
			{
				extra = ReadExtra(decorationData.meta),
				occupied = Count(data)
			};
		}

		private static void AfterGrowth(ref DecorationPositionData decorationData, OvernightState __state)
		{
			ForageTreeSaveData fruitTreeData = DecorationUpdater.fruitTreeData;
			int num = __state.extra;
			if (fruitTreeData != null && fruitTreeData.stage == 7)
			{
				for (int i = 0; i < __state.occupied; i++)
				{
					if (fruitTreeData.golden || Utilities.Chance(0.33f))
					{
						num++;
					}
				}
			}
			num = Mathf.Clamp(num, 0, 99 - Count(fruitTreeData));
			decorationData.meta = WithExtra(decorationData.meta, num);
		}

		private static void Loading(ForageTree __instance, DecorationPositionData decorationData)
		{
			States.GetOrCreateValue(__instance).extra = ReadExtra(decorationData.meta);
		}

		private static void Receiving(ForageTree __instance, byte[] newMeta)
		{
			States.GetOrCreateValue(__instance).extra = ReadExtra(newMeta);
		}

		private static void Saving(ForageTree __instance)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			((Decoration)__instance).meta = WithExtra(((Decoration)__instance).meta, States.GetOrCreateValue(__instance).extra);
			GameSave instance = SingletonBehaviour<GameSave>.Instance;
			CommitMeta((instance != null) ? instance.CurrentWorld : null, ((Decoration)__instance).sceneID, ((Decoration)__instance).Position, ((Decoration)__instance).id, ((Decoration)__instance).meta);
			Refresh(__instance);
		}

		private static void CommitMeta(WorldData world, int scene, Vector3Int position, int id, byte[] meta)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (((world != null) ? world.Decorations : null) != null && world.Decorations.TryGetValue((short)scene, out var value))
			{
				DecorationKey key = default(DecorationKey);
				((DecorationKey)(ref key))..ctor((ushort)((Vector3Int)(ref position)).x, (ushort)((Vector3Int)(ref position)).y, (sbyte)((Vector3Int)(ref position)).z);
				if (value.TryGetValue(key, out var value2) && value2 != null && value2.id == id)
				{
					value2.meta = meta;
				}
			}
		}

		private static void ReceivedShake(Vector3Int position, short scene, byte[] meta)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			GameManager instance = SingletonBehaviour<GameManager>.Instance;
			ForageTree val = default(ForageTree);
			if (scene == ScenePortalManager.ActiveSceneIndex && (Object)(object)instance != (Object)null && instance.TryGetObjectSubTile<ForageTree>(position, ref val))
			{
				((Decoration)val).sceneID = scene;
				GameSave instance2 = SingletonBehaviour<GameSave>.Instance;
				CommitMeta((instance2 != null) ? instance2.CurrentWorld : null, scene, position, ((Decoration)val).id, meta);
			}
		}

		private static void BeforeShake(ForageTree __instance, bool fromLocalPlayer, bool ___requireRelationship, out SpriteRenderer[] __state)
		{
			__state = null;
			if (!fromLocalPlayer)
			{
				return;
			}
			if (___requireRelationship)
			{
				Dictionary<string, float> relationships = SingletonBehaviour<GameSave>.Instance.CurrentSave.characterData.Relationships;
				if (!relationships.ContainsKey("Claude") || relationships["Claude"] < 10f)
				{
					return;
				}
			}
			ExpandHarvest(__instance, out __state);
		}

		private static void BeforeChop(ForageTree __instance, out SpriteRenderer[] __state)
		{
			__state = null;
			if ((Object)(object)__instance.seedItem != (Object)null)
			{
				ExpandHarvest(__instance, out __state);
			}
		}

		private static void ExpandHarvest(ForageTree tree, out SpriteRenderer[] original)
		{
			original = null;
			TreeState orCreateValue = States.GetOrCreateValue(tree);
			if (orCreateValue.extra > 0 && tree.spots != null && tree.spots.Length == 3)
			{
				original = tree.spots;
				SpriteRenderer[] array = (SpriteRenderer[])(object)new SpriteRenderer[3 + orCreateValue.extra];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = original[i % 3];
				}
				tree.spots = array;
				orCreateValue.extra = 0;
			}
		}

		private static void AfterHarvest(ForageTree __instance, SpriteRenderer[] __state)
		{
			if (__state != null)
			{
				__instance.spots = __state;
			}
			if ((Object)(object)__instance != (Object)null)
			{
				Refresh(__instance);
			}
		}

		private static void Visual(Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				if (!reportedVisualError)
				{
					log.LogWarning((object)("Could not refresh fruit notification: " + ex));
				}
				reportedVisualError = true;
			}
		}

		private static void Refresh(ForageTree __instance)
		{
			Visual(delegate
			{
				RefreshCore(__instance);
			});
		}

		private static void RefreshCore(ForageTree __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			TreeState state = States.GetOrCreateValue(__instance);
			int num = Count(__instance.data) + state.extra;
			if (num <= 3)
			{
				if ((Object)(object)state.bubble != (Object)null)
				{
					((Component)state.bubble).gameObject.SetActive(false);
				}
			}
			else if ((Object)(object)state.bubble != (Object)null)
			{
				UpdateBubble(__instance, state, num);
			}
			else
			{
				if (state.loading)
				{
					return;
				}
				state.loading = true;
				Database.GetData<ItemData>(10684, (Action<ItemData>)delegate(ItemData item)
				{
					Visual(delegate
					{
						//IL_0146: Unknown result type (might be due to invalid IL or missing references)
						//IL_014b: Unknown result type (might be due to invalid IL or missing references)
						//IL_0172: Unknown result type (might be due to invalid IL or missing references)
						//IL_017c: Unknown result type (might be due to invalid IL or missing references)
						//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
						//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
						//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
						//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
						//IL_018c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0191: Unknown result type (might be due to invalid IL or missing references)
						//IL_0255: 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_026e: Unknown result type (might be due to invalid IL or missing references)
						//IL_0279: Unknown result type (might be due to invalid IL or missing references)
						//IL_0283: Unknown result type (might be due to invalid IL or missing references)
						//IL_028d: Unknown result type (might be due to invalid IL or missing references)
						state.loading = false;
						if (!((Object)(object)__instance == (Object)null) && Count(__instance.data) + state.extra > 3)
						{
							UseItem useItem = item.useItem;
							Placeable val = (Placeable)(object)((useItem is Placeable) ? useItem : null);
							if (val != null)
							{
								Decoration decoration = val.Decoration;
								CraftingTable val2 = (CraftingTable)(object)((decoration is CraftingTable) ? decoration : null);
								if (val2 != null)
								{
									object? value = AccessTools.Field(typeof(CraftingTable), "craftingUI").GetValue(val2);
									CraftingUI val3 = (CraftingUI)((value is CraftingUI) ? value : null);
									object? value2 = AccessTools.Field(typeof(CraftingTable), "_notificationBubblePrefab").GetValue(val2);
									CraftingNotificationBubble val4 = (CraftingNotificationBubble)((value2 is CraftingNotificationBubble) ? value2 : null);
									if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.notificationContainer == (Object)null) && !((Object)(object)val4 == (Object)null))
									{
										Transform val5 = Object.Instantiate<Transform>(val3.notificationContainer, ((Component)__instance).transform, false);
										((Object)val5).name = "HiccupsFruitNotification";
										for (int num2 = val5.childCount - 1; num2 >= 0; num2--)
										{
											GameObject gameObject = ((Component)val5.GetChild(num2)).gameObject;
											gameObject.SetActive(false);
											Object.Destroy((Object)(object)gameObject);
										}
										Vector3 position = ((Component)__instance.spots[0]).transform.position;
										SpriteRenderer[] spots = __instance.spots;
										foreach (SpriteRenderer val6 in spots)
										{
											if (((Component)val6).transform.position.y > position.y)
											{
												position = ((Component)val6).transform.position;
											}
										}
										position.x = ((Decoration)__instance).Center.x;
										val5.position = position + new Vector3(0f, 0.5f, -0.5f);
										((Component)val5).gameObject.SetActive(true);
										GraphicRaycaster[] componentsInChildren = ((Component)val5).GetComponentsInChildren<GraphicRaycaster>(true);
										for (int i = 0; i < componentsInChildren.Length; i++)
										{
											((Behaviour)componentsInChildren[i]).enabled = false;
										}
										state.bubble = Object.Instantiate<CraftingNotificationBubble>(val4, val5, false);
										RectTransform component = ((Component)state.bubble).GetComponent<RectTransform>();
										Vector2 val7 = default(Vector2);
										((Vector2)(ref val7))..ctor(0.5f, 0f);
										component.anchorMax = val7;
										component.anchorMin = val7;
										component.pivot = new Vector2(0.5f, 0f);
										component.anchoredPosition = Vector2.zero;
										((Transform)component).localScale = Vector3.one * (2f / 3f);
										Graphic[] componentsInChildren2 = ((Component)state.bubble).GetComponentsInChildren<Graphic>(true);
										for (int i = 0; i < componentsInChildren2.Length; i++)
										{
											componentsInChildren2[i].raycastTarget = false;
										}
										UpdateBubble(__instance, state, Count(__instance.data) + state.extra);
									}
								}
							}
						}
					});
				}, (Action)null);
			}
		}

		private static void UpdateBubble(ForageTree tree, TreeState state, int total)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)state.bubble.notificationText).text = "x" + total;
			((Component)state.bubble).gameObject.SetActive(true);
			State state2 = Random.state;
			int num;
			try
			{
				num = (int)GetFruit.Invoke(tree, new object[1] { 0 });
			}
			finally
			{
				Random.state = state2;
			}
			Database.GetData<ItemData>(num, (Action<ItemData>)delegate(ItemData item)
			{
				Visual(delegate
				{
					if (!((Object)(object)tree == (Object)null) && !((Object)(object)state.bubble == (Object)null))
					{
						state.bubble.notificationImage.sprite = item.icon;
						state.bubble.notificationImage.preserveAspect = true;
					}
				});
			}, (Action)null);
		}
	}
	internal static class HomeSleepRules
	{
		internal static bool IsPlayerHome(string scene)
		{
			if (string.IsNullOrEmpty(scene))
			{
				return false;
			}
			switch (scene)
			{
			default:
				return Regex.IsMatch(scene, "\\ATier[1-3]House[0-7]\\z");
			case "NelvariPlayerHouse":
			case "WithergatePlayerApartment":
			case "GCMainDistrictPlayerApartment":
				return true;
			}
		}
	}
	internal sealed class ItemTooltipExtensions
	{
		private sealed class Display
		{
			internal int Item;

			internal int Height;

			internal string Name;

			internal string Description;

			internal string Status;
		}

		[ThreadStatic]
		private static int itemContext;

		private static readonly Dictionary<Tooltip, Display> displays = new Dictionary<Tooltip, Display>();

		private static ManualLogSource log;

		private static float nextRefresh;

		private static bool installed;

		private static readonly List<Func<int, string>> providers = new List<Func<int, string>>();

		internal static void Add(ManualLogSource logger, Func<int, string> provider)
		{
			providers.Add(provider);
			if (!installed)
			{
				installed = true;
				Install(logger);
			}
		}

		private static string Status(int id)
		{
			return string.Concat(providers.Select((Func<int, string> provider) => provider(id)));
		}

		private static void Install(ManualLogSource logger)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_010d: Expected O, but got Unknown
			log = logger;
			Harmony val = new Harmony("com.hiccups.sunhaven.qolfixes.itemtooltips");
			MethodInfo[] array = (from method in (from type in typeof(Item).Assembly.GetTypes()
					where typeof(Item).IsAssignableFrom(type) || HasItemParent(type)
					select type).SelectMany((Type type) => type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
				where method.Name.Contains("<GetToolTip>") && method.GetParameters().Length == 1 && typeof(ItemData).IsAssignableFrom(method.GetParameters()[0].ParameterType)
				select method).ToArray();
			val.Patch((MethodBase)AccessTools.Method(typeof(Tooltip), "SetText", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ItemTooltipExtensions), "SetText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo in array2)
			{
				val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ItemTooltipExtensions), "Enter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ItemTooltipExtensions), "Leave", (Type[])null), (HarmonyMethod)null);
			}
			log.LogInfo((object)("Item tooltip extensions enabled for " + array.Length + " item callbacks"));
		}

		private static bool HasItemParent(Type type)
		{
			Type declaringType = type.DeclaringType;
			while (declaringType != null)
			{
				if (typeof(Item).IsAssignableFrom(declaringType))
				{
					return true;
				}
				declaringType = declaringType.DeclaringType;
			}
			return false;
		}

		private static void Enter(object[] __args, out int __state)
		{
			__state = itemContext;
			object obj = __args[0];
			itemContext = ((ItemData)(((obj is ItemData) ? obj : null)?)).id ?? 0;
		}

		private static void Leave(int __state)
		{
			itemContext = __state;
		}

		private static void SetText(Tooltip __instance, string name, ref string description, int lineHeight)
		{
			if (itemContext <= 0)
			{
				displays.Remove(__instance);
				return;
			}
			Display display = new Display
			{
				Item = itemContext,
				Name = name,
				Description = description,
				Height = lineHeight
			};
			display.Status = Status(display.Item);
			displays[__instance] = display;
			if (!string.IsNullOrEmpty(display.Status))
			{
				description = "<align=center><line-height=100%>" + display.Status.TrimStart('\n', '\r') + "\n\n</line-height></align>" + description;
			}
		}

		internal static void Tick()
		{
			if (Time.unscaledTime < nextRefresh)
			{
				return;
			}
			nextRefresh = Time.unscaledTime + 0.5f;
			KeyValuePair<Tooltip, Display>[] array = displays.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<Tooltip, Display> keyValuePair = array[i];
				if ((Object)(object)keyValuePair.Key == (Object)null)
				{
					displays.Remove(keyValuePair.Key);
				}
				else if (((Component)keyValuePair.Key).gameObject.activeInHierarchy && !(Status(keyValuePair.Value.Item) == keyValuePair.Value.Status))
				{
					int num = itemContext;
					try
					{
						itemContext = keyValuePair.Value.Item;
						keyValuePair.Key.SetText(keyValuePair.Value.Name, keyValuePair.Value.Description, keyValuePair.Value.Height);
					}
					finally
					{
						itemContext = num;
					}
				}
			}
		}
	}
	internal sealed class MuseumCatalog
	{
		internal sealed class BundleDefinition
		{
			public string Progress;

			public string Name;

			public readonly Dictionary<short, DonationRequirement> Slots = new Dictionary<short, DonationRequirement>();
		}

		private readonly Dictionary<int, BundleDefinition> definitions = new Dictionary<int, BundleDefinition>();

		private bool catalogLoading;

		private bool catalogReady;

		private string catalogError;

		private float retryAfter;

		private GameSave loadingHost;

		private readonly ManualLogSource log = Logger.CreateLogSource("HiccupsQOLFixes.MuseumCatalog");

		internal static MuseumCatalog Instance;

		private static readonly FieldInfo InventoryPanel = AccessTools.Field(typeof(Inventory), "_inventoryPanel");

		internal Dictionary<int, BundleDefinition> Definitions => definitions;

		internal bool Ready => catalogReady;

		internal bool Loading => catalogLoading;

		internal string Error => catalogError;

		private static bool IsMuseumScene(int scene)
		{
			return MuseumDonation.IsMuseumScene(scene);
		}

		internal void EnsureLoaded()
		{
			if (catalogLoading && !Object.op_Implicit((Object)(object)loadingHost))
			{
				catalogLoading = false;
			}
			GameSave instance = SingletonBehaviour<GameSave>.Instance;
			if (!catalogReady && !catalogLoading && Object.op_Implicit((Object)(object)instance) && Time.realtimeSinceStartup >= retryAfter)
			{
				loadingHost = instance;
				((MonoBehaviour)instance).StartCoroutine(LoadCatalogSafely());
			}
		}

		internal void Tick()
		{
			GameSave instance = SingletonBehaviour<GameSave>.Instance;
			if (((instance != null) ? instance.CurrentWorld : null) != null && (Object)(object)SceneSettingsManager.Instance != (Object)null)
			{
				EnsureLoaded();
			}
		}

		private