Decompiled source of Glorpheim v1.5.0

glorpheim.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Glorpheim.Configuration;
using Glorpheim.Features;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("glorpheim")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0+bf56bd51b2b8b50029c220db45a3e0aa04d0413e")]
[assembly: AssemblyProduct("glorpheim")]
[assembly: AssemblyTitle("glorpheim")]
[assembly: AssemblyVersion("1.5.0.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 Glorpheim
{
	[BepInPlugin("com.rafael.glorpheim", "glorpheim", "1.5.0")]
	public sealed class GlorpheimPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.rafael.glorpheim";

		public const string PluginName = "glorpheim";

		public const string PluginVersion = "1.5.0";

		private Harmony _harmony;

		internal static GlorpheimPlugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static ModConfig Cfg { get; private set; }

		private void Awake()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigSync configSync = new ConfigSync("com.rafael.glorpheim")
			{
				DisplayName = "glorpheim",
				CurrentVersion = "1.5.0",
				MinimumRequiredVersion = "1.5.0",
				ModRequired = false
			};
			Cfg = new ModConfig(((BaseUnityPlugin)this).Config, configSync);
			_harmony = new Harmony("com.rafael.glorpheim");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			InstantRested.Init();
			FloatingDrops.Init();
			BiggerStacks.Init();
			Log.LogInfo((object)"glorpheim 1.5.0 loaded");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace Glorpheim.Features
{
	[HarmonyPatch]
	internal static class AutoRepair
	{
		private static readonly Func<InventoryGui, bool> HaveRepairableItems = AccessTools.MethodDelegate<Func<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "HaveRepairableItems", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<InventoryGui> RepairOneItem = AccessTools.MethodDelegate<Action<InventoryGui>>(AccessTools.Method(typeof(InventoryGui), "RepairOneItem", (Type[])null, (Type[])null), (object)null, true);

		private static Coroutine _running;

		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		[HarmonyPostfix]
		private static void CraftingStation_Interact_Postfix(CraftingStation __instance, Humanoid user, bool repeat)
		{
			if (repeat || !GlorpheimPlugin.Cfg.AutoRepairEnabled.Value || !__instance.m_canRepair)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)user != (Object)(object)localPlayer) && !((Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)(object)__instance))
			{
				if (_running != null)
				{
					((MonoBehaviour)GlorpheimPlugin.Instance).StopCoroutine(_running);
				}
				_running = ((MonoBehaviour)GlorpheimPlugin.Instance).StartCoroutine(RepairAll(__instance));
			}
		}

		private static IEnumerator RepairAll(CraftingStation station)
		{
			int repaired = 0;
			while (repaired < 100)
			{
				InventoryGui instance = InventoryGui.instance;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || !InventoryGui.IsVisible() || (Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)(object)station || !HaveRepairableItems(instance))
				{
					break;
				}
				RepairOneItem(instance);
				repaired++;
				float value = GlorpheimPlugin.Cfg.AutoRepairDelay.Value;
				if (value > 0f)
				{
					yield return (object)new WaitForSeconds(value);
				}
			}
			if (repaired > 1 && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, $"Repaired {repaired} items", 0, (Sprite)null, false);
			}
			_running = null;
		}
	}
	[HarmonyPatch]
	internal static class BiggerStacks
	{
		[HarmonyPatch]
		private static class KeepStacksOnLoad
		{
			private static MethodBase TargetMethod()
			{
				return typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(delegate(MethodInfo m)
				{
					ParameterInfo[] parameters = m.GetParameters();
					return m.Name == "AddItem" && parameters.Length > 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int);
				});
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				foreach (CodeInstruction instruction in instructions)
				{
					if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, MaxStackSize))
					{
						yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(BiggerStacks), "LoadLimit", (Type[])null, (Type[])null)), instruction);
					}
					else
					{
						yield return instruction;
					}
				}
			}
		}

		private static readonly FieldInfo LoadedItems = AccessTools.Field(typeof(ItemDrop), "s_instances");

		private static readonly FieldInfo MaxStackSize = AccessTools.Field(typeof(SharedData), "m_maxStackSize");

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

		private static string _parsedItemsSource;

		private static HashSet<string> _items = new HashSet<string>();

		private static HashSet<string> FoodIngredients = new HashSet<string>();

		internal static void Init()
		{
			GlorpheimPlugin.Cfg.BiggerStacksEnabled.SettingChanged += delegate
			{
				ApplyAll();
			};
			GlorpheimPlugin.Cfg.BiggerStacksMultiplier.SettingChanged += delegate
			{
				ApplyAll();
			};
			GlorpheimPlugin.Cfg.BiggerStacksIncludeFood.SettingChanged += delegate
			{
				ApplyAll();
			};
			GlorpheimPlugin.Cfg.BiggerStacksIncludeFoodIngredients.SettingChanged += delegate
			{
				ApplyAll();
			};
			GlorpheimPlugin.Cfg.BiggerStacksItems.SettingChanged += delegate
			{
				ApplyAll();
			};
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void ObjectDBAwakePostfix()
		{
			ApplyAll();
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void CopyOtherDBPostfix()
		{
			ApplyAll();
		}

		[HarmonyPatch(typeof(ItemDrop), "Awake")]
		[HarmonyPostfix]
		private static void ItemDropAwakePostfix(ItemDrop __instance)
		{
			Apply(__instance.m_itemData);
		}

		private static int LoadLimit(SharedData shared)
		{
			if (shared.m_maxStackSize <= 1)
			{
				return shared.m_maxStackSize;
			}
			return int.MaxValue;
		}

		private static void ApplyAll()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			FindFoodIngredients(instance);
			foreach (GameObject item in instance.m_items)
			{
				ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
				if (!((Object)(object)val == (Object)null))
				{
					if (!VanillaStack.ContainsKey(((Object)item).name))
					{
						VanillaStack[((Object)item).name] = val.m_itemData.m_shared.m_maxStackSize;
					}
					Apply(val.m_itemData, ((Object)item).name);
				}
			}
			if (LoadedItems?.GetValue(null) is List<ItemDrop> list)
			{
				foreach (ItemDrop item2 in list)
				{
					if ((Object)(object)item2 != (Object)null)
					{
						Apply(item2.m_itemData);
					}
				}
			}
			Inventory val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null);
			if (val2 == null)
			{
				return;
			}
			foreach (ItemData allItem in val2.GetAllItems())
			{
				Apply(allItem);
			}
		}

		private static void Apply(ItemData item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				Apply(item, ((Object)item.m_dropPrefab).name);
			}
		}

		private static void Apply(ItemData item, string prefabName)
		{
			if (item?.m_shared != null && VanillaStack.TryGetValue(prefabName, out var value) && value > 1)
			{
				bool flag = GlorpheimPlugin.Cfg.BiggerStacksEnabled.Value && (IsListed(prefabName) || (GlorpheimPlugin.Cfg.BiggerStacksIncludeFood.Value && IsFood(item.m_shared)) || (GlorpheimPlugin.Cfg.BiggerStacksIncludeFoodIngredients.Value && FoodIngredients.Contains(prefabName)));
				item.m_shared.m_maxStackSize = (flag ? (value * GlorpheimPlugin.Cfg.BiggerStacksMultiplier.Value) : value);
			}
		}

		private static void FindFoodIngredients(ObjectDB db)
		{
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			foreach (Recipe recipe in db.m_recipes)
			{
				if ((Object)(object)recipe == (Object)null || !recipe.m_enabled || (Object)(object)recipe.m_item == (Object)null)
				{
					continue;
				}
				Requirement[] resources = recipe.m_resources;
				foreach (Requirement val in resources)
				{
					if ((Object)(object)val?.m_resItem != (Object)null)
					{
						list.Add(new KeyValuePair<string, string>(((Object)val.m_resItem).name, ((Object)recipe.m_item).name));
					}
				}
			}
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			foreach (GameObject item in db.m_items)
			{
				ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
				PieceTable val3 = (((Object)(object)val2 != (Object)null) ? val2.m_itemData.m_shared.m_buildPieces : null);
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				foreach (GameObject piece in val3.m_pieces)
				{
					if ((Object)(object)piece == (Object)null || !hashSet.Add(piece))
					{
						continue;
					}
					CookingStation componentInChildren = piece.GetComponentInChildren<CookingStation>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						list.AddRange(from c in componentInChildren.m_conversion
							where (Object)(object)c?.m_from != (Object)null && (Object)(object)c.m_to != (Object)null
							select new KeyValuePair<string, string>(((Object)c.m_from).name, ((Object)c.m_to).name));
					}
					Smelter componentInChildren2 = piece.GetComponentInChildren<Smelter>();
					if ((Object)(object)componentInChildren2 != (Object)null)
					{
						list.AddRange(from c in componentInChildren2.m_conversion
							where (Object)(object)c?.m_from != (Object)null && (Object)(object)c.m_to != (Object)null
							select new KeyValuePair<string, string>(((Object)c.m_from).name, ((Object)c.m_to).name));
					}
				}
			}
			HashSet<string> hashSet2 = new HashSet<string>(from p in db.m_items
				select (!((Object)(object)p != (Object)null)) ? null : p.GetComponent<ItemDrop>() into d
				where (Object)(object)d != (Object)null && IsFood(d.m_itemData.m_shared)
				select ((Object)d).name);
			HashSet<string> hashSet3 = new HashSet<string>();
			bool flag = true;
			while (flag)
			{
				flag = false;
				foreach (KeyValuePair<string, string> item2 in list)
				{
					if (hashSet2.Contains(item2.Value) && hashSet2.Add(item2.Key))
					{
						hashSet3.Add(item2.Key);
						flag = true;
					}
				}
			}
			if (!hashSet3.SetEquals(FoodIngredients))
			{
				FoodIngredients = hashSet3;
				GlorpheimPlugin.Log.LogInfo((object)string.Format("BiggerStacks food ingredients ({0}): {1}", hashSet3.Count, string.Join(", ", hashSet3.OrderBy((string n) => n))));
			}
		}

		private static bool IsListed(string prefabName)
		{
			string value = GlorpheimPlugin.Cfg.BiggerStacksItems.Value;
			if (value != _parsedItemsSource)
			{
				_items = new HashSet<string>(from s in value.Split(new char[1] { ',' })
					select s.Trim() into s
					where s.Length > 0
					select s, StringComparer.OrdinalIgnoreCase);
				_parsedItemsSource = value;
			}
			return _items.Contains(prefabName);
		}

		private static bool IsFood(SharedData shared)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)shared.m_itemType == 2)
			{
				if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f))
				{
					return shared.m_foodEitr > 0f;
				}
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class DeathMessages
	{
		private const string RpcName = "Glorpheim_DeathMessage";

		private static readonly FieldRef<Character, HitData> LastHitRef = AccessTools.FieldRefAccess<Character, HitData>("m_lastHit");

		private static readonly FieldRef<Chat, float> HideTimerRef = AccessTools.FieldRefAccess<Chat, float>("m_hideTimer");

		private static readonly Random s_random = new Random();

		private static readonly string[] SlainBy = new string[7] { "{0} was slain by {1}.", "{0} was murdered by {1}.", "{0} was cut down by {1}.", "{0} was mauled by {1}.", "{0} was removed from this world by {1}.", "{0} tried to run from {1}.", "{0}'s corpse run was sponsored by {1}." };

		private static readonly string[] Fall = new string[4] { "{0} fell to their death.", "{0} didn't bounce.", "{0} invented gravity.", "{0} thought they could fly." };

		private static readonly string[] Drowning = new string[3] { "{0} drowned.", "{0} forgot to breathe.", "{0} was swallowed by the sea." };

		private static readonly string[] Burning = new string[2] { "{0} was burned to death.", "{0} went up in flames." };

		private static readonly string[] Freezing = new string[2] { "{0} froze to death.", "{0} should have brought a cloak." };

		private static readonly string[] PoisonedBy = new string[2] { "{0} was poisoned to death by {1}.", "{0} couldn't shake off {1}'s poison." };

		private static readonly string[] Poisoned = new string[1] { "{0} was poisoned to death." };

		private static readonly string[] Self = new string[2] { "{0} took the easy way out.", "{0} gave up." };

		private static readonly string[] Unknown = new string[2] { "{0} died.", "{0} died mysteriously." };

		[HarmonyPatch(typeof(Game), "Start")]
		[HarmonyPostfix]
		private static void Game_Start_Postfix()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<string>("Glorpheim_DeathMessage", (Action<long, string>)RPC_DeathMessage);
			}
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		[HarmonyPostfix]
		private static void Player_OnDeath_Postfix(Player __instance)
		{
			if (!GlorpheimPlugin.Cfg.DeathMessagesEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ZRoutedRpc.instance == null)
			{
				return;
			}
			try
			{
				string text = Describe(__instance, LastHitRef.Invoke((Character)(object)__instance));
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Glorpheim_DeathMessage", new object[1] { text });
			}
			catch (Exception arg)
			{
				GlorpheimPlugin.Log.LogWarning((object)$"DeathMessages: could not announce death: {arg}");
			}
		}

		private static void RPC_DeathMessage(long sender, string text)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!GlorpheimPlugin.Cfg.DeathMessagesEnabled.Value || string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			text = Sanitize(text);
			if (text.Length > 300)
			{
				text = text.Substring(0, 300);
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated())
			{
				GlorpheimPlugin.Log.LogInfo((object)text);
				return;
			}
			Chat instance = Chat.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				string text2 = ColorUtility.ToHtmlStringRGBA(GlorpheimPlugin.Cfg.DeathMessagesColor.Value);
				((Terminal)instance).AddString("<color=#" + text2 + ">" + text + "</color>");
				HideTimerRef.Invoke(instance) = 0f;
			}
		}

		private static string Describe(Player victim, HitData hit)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected I4, but got Unknown
			string text = Sanitize(victim.GetPlayerName());
			if (hit == null)
			{
				return Pick(Unknown, text);
			}
			Character attacker = hit.GetAttacker();
			string text2 = (((Object)(object)attacker != (Object)null) ? KillerName(attacker) : null);
			HitType hitType = hit.m_hitType;
			switch (hitType - 1)
			{
			case 0:
			case 1:
				if (text2 == null)
				{
					return Pick(Unknown, text);
				}
				return Pick(SlainBy, text, text2);
			case 2:
				return Pick(Fall, text);
			case 3:
				return Pick(Drowning, text);
			case 4:
				if (text2 == null)
				{
					return Pick(Burning, text);
				}
				return Pick(SlainBy, text, text2);
			case 5:
				return Pick(Freezing, text);
			case 6:
				if (text2 == null)
				{
					return Pick(Poisoned, text);
				}
				return Pick(PoisonedBy, text, text2);
			case 7:
				return text + " was swept away by the water.";
			case 8:
				return text + " was suffocated by smoke.";
			case 9:
				return text + " fell off the edge of the world.";
			case 10:
				return text + " was crushed.";
			case 11:
				return text + " was run over by a cart.";
			case 12:
				return text + " was crushed by a falling tree.";
			case 13:
				return Pick(Self, text);
			case 14:
				return text + " was buried under a collapsing building.";
			case 15:
				return text + " was shot by a ballista.";
			case 16:
				return text + " was hit by a boat.";
			case 17:
				return text + " was impaled by a falling stalactite.";
			case 18:
				return text + " was flattened by a catapult.";
			case 19:
				return text + " was burned to ash by cinders.";
			case 20:
				return text + " was boiled alive.";
			case 21:
				return text + " tried to swim in lava.";
			case 22:
				return text + " was incinerated.";
			case 23:
				return text + " was crushed by a drawbridge.";
			default:
				if (text2 == null)
				{
					return Pick(Unknown, text);
				}
				return Pick(SlainBy, text, text2);
			}
		}

		private static string KillerName(Character attacker)
		{
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (val != null)
			{
				return Sanitize(val.GetPlayerName());
			}
			string text = Sanitize(Localization.instance.Localize(attacker.m_name));
			if (attacker.IsBoss())
			{
				return text;
			}
			if (attacker.IsTamed())
			{
				Tameable component = ((Component)attacker).GetComponent<Tameable>();
				string text2 = (((Object)(object)component != (Object)null) ? Sanitize(component.GetText()).Trim() : "");
				if (text2.Length <= 0)
				{
					return "a tamed " + text;
				}
				return text2 + " the " + text;
			}
			int num = attacker.GetLevel() - 1;
			if (num > 0)
			{
				return $"a {num}-star {text}";
			}
			return Article(text) + " " + text;
		}

		private static string Article(string noun)
		{
			if (noun.Length <= 0 || "aeiouAEIOU".IndexOf(noun[0]) < 0)
			{
				return "a";
			}
			return "an";
		}

		private static string Pick(string[] templates, params object[] args)
		{
			return string.Format(templates[s_random.Next(templates.Length)], args);
		}

		private static string Sanitize(string text)
		{
			return (text ?? "").Replace('<', ' ').Replace('>', ' ');
		}
	}
	[HarmonyPatch(typeof(EnvMan), "SetTargetWind")]
	internal static class FairWinds
	{
		private const float WorldRadius = 10500f;

		[HarmonyPrefix]
		private static void Prefix(EnvMan __instance, ref Vector3 dir)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			if (!GlorpheimPlugin.Cfg.FairWindsEnabled.Value || __instance.m_debugWind)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).InInterior() || Utils.LengthXZ(((Component)localPlayer).transform.position) > 10500f - __instance.m_edgeOfWorldWidth)
			{
				return;
			}
			Ship localShip = Ship.GetLocalShip();
			if ((Object)(object)localShip == (Object)null)
			{
				return;
			}
			Vector3 forward = ((Component)localShip).transform.forward;
			forward.y = 0f;
			if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f))
			{
				((Vector3)(ref forward)).Normalize();
				float value = GlorpheimPlugin.Cfg.FairWindsMaxWindAngle.Value;
				float num = Vector3.SignedAngle(forward, dir, Vector3.up);
				if (Mathf.Abs(num) > value)
				{
					dir = Quaternion.AngleAxis(Mathf.Sign(num) * value, Vector3.up) * forward;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Plant), "GetGrowTime")]
	internal static class FasterCrops
	{
		[HarmonyPostfix]
		private static void Postfix(ref float __result)
		{
			if (GlorpheimPlugin.Cfg.FasterCropsEnabled.Value)
			{
				float value = GlorpheimPlugin.Cfg.FasterCropsSpeedMultiplier.Value;
				if (value > 0f)
				{
					__result /= value;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class FasterStations
	{
		private static readonly FieldInfo CookTimeField = AccessTools.Field(typeof(ItemConversion), "m_cookTime");

		private static readonly MethodInfo OvercookFactorMethod = AccessTools.Method(typeof(FasterStations), "OvercookFactor", (Type[])null, (Type[])null);

		private static float s_cookingMultiplier;

		private static float Multiplier()
		{
			if (!GlorpheimPlugin.Cfg.FasterStationsEnabled.Value)
			{
				return 0f;
			}
			float value = GlorpheimPlugin.Cfg.FasterStationsSpeedMultiplier.Value;
			if (!(value > 0f))
			{
				return 0f;
			}
			return value;
		}

		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		[HarmonyPrefix]
		private static void Smelter_Prefix(Smelter __instance, out float __state)
		{
			__state = __instance.m_secPerProduct;
			float num = Multiplier();
			if (num > 0f)
			{
				__instance.m_secPerProduct = __state / num;
			}
		}

		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		[HarmonyPostfix]
		private static void Smelter_Postfix(Smelter __instance, float __state)
		{
			__instance.m_secPerProduct = __state;
		}

		private static float OvercookFactor()
		{
			if (!(s_cookingMultiplier > 0f))
			{
				return 2f;
			}
			return 1f + s_cookingMultiplier;
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		[HarmonyPrefix]
		private static void CookingStation_Prefix(CookingStation __instance, out float __state)
		{
			s_cookingMultiplier = Multiplier();
			__state = s_cookingMultiplier;
			if (__state <= 0f)
			{
				return;
			}
			foreach (ItemConversion item in __instance.m_conversion)
			{
				item.m_cookTime /= __state;
			}
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		[HarmonyPostfix]
		private static void CookingStation_Postfix(CookingStation __instance, float __state)
		{
			s_cookingMultiplier = 0f;
			if (__state <= 0f)
			{
				return;
			}
			foreach (ItemConversion item in __instance.m_conversion)
			{
				item.m_cookTime *= __state;
			}
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> CookingStation_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 0; i + 2 < list.Count; i++)
			{
				if (CodeInstructionExtensions.LoadsField(list[i], CookTimeField, false) && list[i + 1].opcode == OpCodes.Ldc_R4 && list[i + 1].operand is float num && num == 2f && list[i + 2].opcode == OpCodes.Mul)
				{
					list[i + 1] = new CodeInstruction(OpCodes.Call, (object)OvercookFactorMethod);
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				GlorpheimPlugin.Log.LogWarning((object)"FasterStations: overcook check not found in CookingStation.UpdateCooking; items will burn faster too.");
			}
			return list;
		}

		[HarmonyPatch(typeof(Fermenter), "GetStatus")]
		[HarmonyPrefix]
		private static void Fermenter_Prefix(Fermenter __instance, out float __state)
		{
			__state = __instance.m_fermentationDuration;
			float num = Multiplier();
			if (num > 0f)
			{
				__instance.m_fermentationDuration = __state / num;
			}
		}

		[HarmonyPatch(typeof(Fermenter), "GetStatus")]
		[HarmonyPostfix]
		private static void Fermenter_Postfix(Fermenter __instance, float __state)
		{
			__instance.m_fermentationDuration = __state;
		}

		[HarmonyPatch(typeof(Beehive), "UpdateBees")]
		[HarmonyPrefix]
		private static void Beehive_Prefix(Beehive __instance, out float __state)
		{
			__state = __instance.m_secPerUnit;
			float num = Multiplier();
			if (num > 0f)
			{
				__instance.m_secPerUnit = __state / num;
			}
		}

		[HarmonyPatch(typeof(Beehive), "UpdateBees")]
		[HarmonyPostfix]
		private static void Beehive_Postfix(Beehive __instance, float __state)
		{
			__instance.m_secPerUnit = __state;
		}

		[HarmonyPatch(typeof(SapCollector), "UpdateTick")]
		[HarmonyPrefix]
		private static void SapCollector_Prefix(SapCollector __instance, out float __state)
		{
			__state = __instance.m_secPerUnit;
			float num = Multiplier();
			if (num > 0f)
			{
				__instance.m_secPerUnit = __state / num;
			}
		}

		[HarmonyPatch(typeof(SapCollector), "UpdateTick")]
		[HarmonyPostfix]
		private static void SapCollector_Postfix(SapCollector __instance, float __state)
		{
			__instance.m_secPerUnit = __state;
		}
	}
	[HarmonyPatch]
	internal static class FloatingDrops
	{
		private static readonly FieldRef<ItemDrop, Floating> CachedFloating = AccessTools.FieldRefAccess<ItemDrop, Floating>("m_floating");

		private static readonly FieldInfo LoadedItems = AccessTools.Field(typeof(ItemDrop), "s_instances");

		internal static void Init()
		{
			GlorpheimPlugin.Cfg.FloatingDropsEnabled.SettingChanged += delegate
			{
				ApplyToLoadedItems();
			};
		}

		[HarmonyPatch(typeof(ItemDrop), "Awake")]
		[HarmonyPostfix]
		private static void ItemDrop_Awake_Postfix(ItemDrop __instance)
		{
			Apply(__instance, seedLiquidLevel: false);
		}

		private static void ApplyToLoadedItems()
		{
			if (LoadedItems.GetValue(null) is List<ItemDrop> list)
			{
				for (int i = 0; i < list.Count; i++)
				{
					Apply(list[i], seedLiquidLevel: true);
				}
			}
		}

		private static void Apply(ItemDrop item, bool seedLiquidLevel)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			Floating component = ((Component)item).GetComponent<Floating>();
			bool flag = (Object)(object)component != (Object)null && AddedByUs(item);
			if (!GlorpheimPlugin.Cfg.FloatingDropsEnabled.Value)
			{
				if (flag)
				{
					Object.Destroy((Object)(object)component);
					CachedFloating.Invoke(item) = null;
				}
			}
			else if (!((Object)(object)component != (Object)null) && CanFloat(item))
			{
				component = ((Component)item).gameObject.AddComponent<Floating>();
				CachedFloating.Invoke(item) = component;
				if (seedLiquidLevel)
				{
					SeedLiquidLevel(component, ((Component)item).transform.position);
				}
			}
		}

		private static bool AddedByUs(ItemDrop item)
		{
			GameObject dropPrefab = item.m_itemData.m_dropPrefab;
			if ((Object)(object)dropPrefab != (Object)null)
			{
				return (Object)(object)dropPrefab.GetComponent<Floating>() == (Object)null;
			}
			return false;
		}

		private static bool CanFloat(ItemDrop item)
		{
			ZNetView component = ((Component)item).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return false;
			}
			if (component.GetZDO().GetBool(ZDOVars.s_piece, false))
			{
				return false;
			}
			if ((Object)(object)((Component)item).GetComponent<Rigidbody>() != (Object)null)
			{
				return (Object)(object)((Component)item).GetComponentInChildren<Collider>() != (Object)null;
			}
			return false;
		}

		private static void SeedLiquidLevel(Floating floating, Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			float liquidLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0);
			if (!(liquidLevel <= position.y))
			{
				floating.Increment((LiquidType)0);
				floating.SetLiquidLevel(liquidLevel, (LiquidType)0, (Component)null);
			}
		}
	}
	[HarmonyPatch]
	internal static class FreeCultivator
	{
		private static bool s_freeToolInUse;

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

		private static string s_toolsSource;

		private static bool IsFreeTool(ItemData item)
		{
			if (item == null || !GlorpheimPlugin.Cfg.FreeCultivatorEnabled.Value)
			{
				return false;
			}
			string text = GlorpheimPlugin.Cfg.FreeCultivatorTools.Value ?? "";
			if (text != s_toolsSource)
			{
				s_tools.Clear();
				string[] array = text.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (text2.Length > 0)
					{
						s_tools.Add(text2);
					}
				}
				s_toolsSource = text;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return s_tools.Contains(((Object)item.m_dropPrefab).name);
			}
			return false;
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		[HarmonyPrefix]
		private static void UpdatePlacement_Prefix(Player __instance)
		{
			s_freeToolInUse = IsFreeTool(((Humanoid)__instance).RightItem);
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		[HarmonyPostfix]
		private static void UpdatePlacement_Postfix()
		{
			s_freeToolInUse = false;
		}

		[HarmonyPatch(typeof(Player), "GetBuildStamina")]
		[HarmonyPostfix]
		private static void GetBuildStamina_Postfix(ref float __result)
		{
			if (s_freeToolInUse)
			{
				__result = 0f;
			}
		}

		[HarmonyPatch(typeof(Player), "GetPlaceDurability")]
		[HarmonyPostfix]
		private static void GetPlaceDurability_Postfix(ItemData tool, ref float __result)
		{
			if (GlorpheimPlugin.Cfg.FreeCultivatorEnabled.Value && (Object)(object)tool?.m_dropPrefab != (Object)null && ((Object)tool.m_dropPrefab).name == "Cultivator")
			{
				__result = 0f;
			}
		}

		[HarmonyPatch(typeof(Player), "HaveStamina")]
		[HarmonyPrefix]
		private static bool HaveStamina_Prefix(ref bool __result)
		{
			if (!s_freeToolInUse)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(Chat), "SendText")]
	internal static class GlobalChat
	{
		[HarmonyPrefix]
		private static bool Prefix(Type type, string text)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			if (!GlorpheimPlugin.Cfg.GlobalChatEnabled.Value || (int)type != 1 || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			Chat.CheckPermissionsAndSendChatMessageRPCsAsync((SendChatMessageRPCHandler)delegate(long user, bool filterText)
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				UserInfo val = default(UserInfo);
				string text2 = default(string);
				Chat.GetChatMessageData(text, filterText, ref val, ref text2);
				ZRoutedRpc.instance.InvokeRoutedRPC(user, "ChatMessage", new object[4]
				{
					((Character)Player.m_localPlayer).GetHeadPoint(),
					1,
					val,
					text2
				});
			});
			return false;
		}
	}
	[HarmonyPatch]
	internal static class InstantRested
	{
		private const float FallbackVanillaDelay = 20f;

		internal static void Init()
		{
			GlorpheimPlugin.Cfg.InstantRestedEnabled.SettingChanged += delegate
			{
				ApplyToLocalPlayer();
			};
			GlorpheimPlugin.Cfg.InstantRestedDelay.SettingChanged += delegate
			{
				ApplyToLocalPlayer();
			};
		}

		[HarmonyPatch(typeof(SE_Cozy), "Setup")]
		[HarmonyPostfix]
		private static void SE_Cozy_Setup_Postfix(SE_Cozy __instance)
		{
			Apply(__instance);
		}

		private static void ApplyToLocalPlayer()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				StatusEffect statusEffect = ((Character)localPlayer).GetSEMan().GetStatusEffect(SEMan.s_statusEffectResting);
				SE_Cozy val = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null);
				if (val != null)
				{
					Apply(val);
				}
			}
		}

		private static void Apply(SE_Cozy se)
		{
			if (((StatusEffect)se).NameHash() == SEMan.s_statusEffectResting)
			{
				se.m_delay = (GlorpheimPlugin.Cfg.InstantRestedEnabled.Value ? GlorpheimPlugin.Cfg.InstantRestedDelay.Value : VanillaDelay());
			}
		}

		private static float VanillaDelay()
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(SEMan.s_statusEffectResting);
				SE_Cozy val = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null);
				if (val != null)
				{
					return val.m_delay;
				}
			}
			return 20f;
		}
	}
	[HarmonyPatch]
	internal static class KeepFoodOnDeath
	{
		[HarmonyPatch(typeof(Player), "OnDeath")]
		[HarmonyPrefix]
		private static void Player_OnDeath_Prefix(Player __instance, out List<Food> __state)
		{
			__state = new List<Food>(__instance.GetFoods());
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		[HarmonyPostfix]
		private static void Player_OnDeath_Postfix(Player __instance, List<Food> __state)
		{
			if (GlorpheimPlugin.Cfg.KeepFoodOnDeathEnabled.Value && __state.Count != 0)
			{
				List<Food> foods = __instance.GetFoods();
				if (foods.Count == 0)
				{
					foods.AddRange(__state);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	internal static class NearbyChestCounts
	{
		private const string NearbyChestsGuid = "NearbyChests";

		private static bool? s_nearbyChestsLoaded;

		private static bool NearbyChestsLoaded
		{
			get
			{
				bool? flag = s_nearbyChestsLoaded;
				if (!flag.HasValue)
				{
					bool? flag2 = (s_nearbyChestsLoaded = Chainloader.PluginInfos.ContainsKey("NearbyChests"));
					return flag2.Value;
				}
				return flag == true;
			}
		}

		[HarmonyPostfix]
		private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result)
		{
			if (__result && !((Object)(object)req.m_resItem == (Object)null) && !((Object)(object)player == (Object)null) && GlorpheimPlugin.Cfg.NearbyChestCountsEnabled.Value && NearbyChestsLoaded)
			{
				int num = req.GetAmount(quality) * craftMultiplier;
				int num2 = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true);
				TMP_Text component = ((Component)elementRoot.Find("res_amount")).GetComponent<TMP_Text>();
				component.textWrappingMode = (TextWrappingModes)0;
				component.overflowMode = (TextOverflowModes)0;
				component.text = $"{num} <size=80%>({num2})</size>";
			}
		}
	}
	[HarmonyPatch]
	internal static class NewRecipeHighlight
	{
		private const string CustomDataKey = "glorpheim.unseen_recipes";

		private const string MarkName = "glorpheim_new";

		private const char Separator = '\n';

		private static readonly FieldInfo AvailableRecipes = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly Type RecipeDataPair = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair");

		private static readonly PropertyInfo PairRecipe = AccessTools.Property(RecipeDataPair, "Recipe");

		private static readonly PropertyInfo PairElement = AccessTools.Property(RecipeDataPair, "InterfaceElement");

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

		private static Player s_loadedFor;

		private static bool s_userSelecting;

		private static bool Enabled => GlorpheimPlugin.Cfg.NewRecipeHighlightEnabled.Value;

		private static HashSet<string> Unseen(Player player)
		{
			if ((Object)(object)s_loadedFor != (Object)(object)player)
			{
				s_loadedFor = player;
				s_unseen.Clear();
				if ((Object)(object)player != (Object)null && player.m_customData.TryGetValue("glorpheim.unseen_recipes", out var value) && !string.IsNullOrEmpty(value))
				{
					s_unseen.UnionWith(value.Split(new char[1] { '\n' }));
				}
			}
			return s_unseen;
		}

		private static void Save(Player player)
		{
			if (s_unseen.Count == 0)
			{
				player.m_customData.Remove("glorpheim.unseen_recipes");
			}
			else
			{
				player.m_customData["glorpheim.unseen_recipes"] = string.Join('\n'.ToString(), s_unseen);
			}
		}

		private static string RecipeKey(Recipe recipe)
		{
			if (!((Object)(object)recipe != (Object)null) || !((Object)(object)recipe.m_item != (Object)null))
			{
				return null;
			}
			return recipe.m_item.m_itemData.m_shared.m_name;
		}

		[HarmonyPatch(typeof(Player), "AddKnownRecipe")]
		[HarmonyPrefix]
		private static void AddKnownRecipe_Prefix(Player __instance, Recipe recipe, out bool __state)
		{
			string text = RecipeKey(recipe);
			__state = text != null && __instance.IsRecipeKnown(text);
		}

		[HarmonyPatch(typeof(Player), "AddKnownRecipe")]
		[HarmonyPostfix]
		private static void AddKnownRecipe_Postfix(Player __instance, Recipe recipe, bool __state)
		{
			string text = RecipeKey(recipe);
			if (!__state && text != null && Enabled && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __instance.IsRecipeKnown(text) && Unseen(__instance).Add(text))
			{
				Save(__instance);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
		[HarmonyPostfix]
		private static void AddRecipeToList_Postfix(InventoryGui __instance, Player player, Recipe recipe)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			string text = RecipeKey(recipe);
			if (text != null && Enabled && !((Object)(object)player == (Object)null) && Unseen(player).Contains(text))
			{
				IList list = (IList)AvailableRecipes.GetValue(__instance);
				if (list.Count != 0)
				{
					AddMark((GameObject)PairElement.GetValue(list[list.Count - 1]));
				}
			}
		}

		private static void AddMark(GameObject row)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Color value = GlorpheimPlugin.Cfg.NewRecipeHighlightColor.Value;
			Transform val = row.transform.Find("selected");
			GameObject val2;
			if ((Object)(object)val != (Object)null)
			{
				val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, row.transform);
				val2.transform.SetSiblingIndex(val.GetSiblingIndex());
				Image[] componentsInChildren = val2.GetComponentsInChildren<Image>(true);
				foreach (Image obj in componentsInChildren)
				{
					((Graphic)obj).color = value;
					((Graphic)obj).raycastTarget = false;
				}
			}
			else
			{
				val2 = new GameObject("glorpheim_new", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				RectTransform val3 = (RectTransform)val2.transform;
				((Transform)val3).SetParent(row.transform, false);
				((Transform)val3).SetAsFirstSibling();
				val3.anchorMin = Vector2.zero;
				val3.anchorMax = Vector2.one;
				Vector2 offsetMin = (val3.offsetMax = Vector2.zero);
				val3.offsetMin = offsetMin;
				Image component = val2.GetComponent<Image>();
				((Graphic)component).color = value;
				((Graphic)component).raycastTarget = false;
			}
			((Object)val2).name = "glorpheim_new";
			val2.SetActive(true);
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedRecipe")]
		[HarmonyPrefix]
		private static void OnSelectedRecipe_Prefix()
		{
			s_userSelecting = true;
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedRecipe")]
		[HarmonyFinalizer]
		private static void OnSelectedRecipe_Finalizer()
		{
			s_userSelecting = false;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")]
		[HarmonyPrefix]
		private static void UpdateRecipeGamepadInput_Prefix()
		{
			s_userSelecting = true;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")]
		[HarmonyFinalizer]
		private static void UpdateRecipeGamepadInput_Finalizer()
		{
			s_userSelecting = false;
		}

		[HarmonyPatch(typeof(InventoryGui), "SetRecipe")]
		[HarmonyPostfix]
		private static void SetRecipe_Postfix(InventoryGui __instance, int index)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!s_userSelecting || index < 0 || (Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			IList list = (IList)AvailableRecipes.GetValue(__instance);
			if (index >= list.Count)
			{
				return;
			}
			string text = RecipeKey((Recipe)PairRecipe.GetValue(list[index]));
			if (text == null || !Unseen(localPlayer).Remove(text))
			{
				return;
			}
			Save(localPlayer);
			foreach (object item in list)
			{
				if (!(RecipeKey((Recipe)PairRecipe.GetValue(item)) != text))
				{
					Transform val = ((GameObject)PairElement.GetValue(item)).transform.Find("glorpheim_new");
					if ((Object)(object)val != (Object)null)
					{
						((Component)val).gameObject.SetActive(false);
					}
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class RecipeSearch
	{
		[HarmonyPatch(typeof(ZInput), "TryGetButtonState")]
		private static class ZInput_TryGetButtonState
		{
			private static bool Prefix(string name, ref bool __result)
			{
				if (!BlockGameInput || name.StartsWith("Mouse", StringComparison.Ordinal))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(ZInput), "TryGetKeyStateLowLevel")]
		private static class ZInput_TryGetKeyStateLowLevel
		{
			private static bool Prefix(KeyCode keyCode, ref bool __result)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Invalid comparison between Unknown and I4
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Invalid comparison between Unknown and I4
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Invalid comparison between Unknown and I4
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Invalid comparison between Unknown and I4
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Invalid comparison between Unknown and I4
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Invalid comparison between Unknown and I4
				if (!BlockGameInput || ((int)keyCode >= 323 && (int)keyCode <= 329) || (int)keyCode == 306 || (int)keyCode == 305 || (int)keyCode == 8 || (int)keyCode == 127)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction<string> <0>__OnTextChanged;

			public static UnityAction <1>__OnClearPressed;
		}

		private const string FieldName = "glorpheim_RecipeSearch";

		private const float Gap = 8f;

		private const float MinWidth = 120f;

		private const float MaxWidth = 320f;

		private const float MaxHeight = 36f;

		private static readonly string[] NoWords = new string[0];

		private static readonly Action<InventoryGui, bool> UpdateCraftingPanel = AccessTools.MethodDelegate<Action<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldInfo BuildSearchField = AccessTools.Field(typeof(BuildUi), "m_searchField");

		private static TMP_InputField s_field;

		private static MethodInfo s_activateInputField;

		private static GameObject s_clearButton;

		private static string[] s_words = NoWords;

		private static int s_blockUntilFrame = -1;

		private static bool s_warnedMissingSource;

		private static bool Enabled => GlorpheimPlugin.Cfg.RecipeSearchEnabled.Value;

		private static bool BlockGameInput
		{
			get
			{
				if ((Object)(object)s_field != (Object)null)
				{
					if (!s_field.isFocused || !((Component)s_field).gameObject.activeInHierarchy)
					{
						return Time.frameCount == s_blockUntilFrame;
					}
					return true;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		[HarmonyPrefix]
		private static void UpdateRecipeList_Prefix(List<Recipe> recipes)
		{
			if (s_words.Length != 0 && Enabled)
			{
				recipes.RemoveAll((Recipe recipe) => !Matches(recipe));
			}
		}

		private static bool Matches(Recipe recipe)
		{
			ItemDrop item = recipe.m_item;
			if ((Object)(object)item == (Object)null)
			{
				return true;
			}
			string text = Localization.instance.Localize(item.m_itemData.m_shared.m_name);
			string name = ((Object)item).name;
			string[] array = s_words;
			foreach (string word in array)
			{
				if (!Contains(text, word) && !Contains(name, word))
				{
					return false;
				}
			}
			return true;
		}

		private static bool Contains(string text, string word)
		{
			return CultureInfo.InvariantCulture.CompareInfo.IndexOf(text, word, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
		}

		private static void SetTerm(string text)
		{
			s_words = (string.IsNullOrEmpty(text) ? NoWords : text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries));
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		private static void SearchFieldFocused_Postfix(ref bool __result)
		{
			if (BlockGameInput)
			{
				__result = true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		[HarmonyPostfix]
		private static void Update_Postfix()
		{
			if (!((Object)(object)s_field == (Object)null) && Enabled && !s_field.isFocused && ((Component)s_field).gameObject.activeInHierarchy && InventoryGui.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !Minimap.IsOpen() && ZInput.GetKeyDown((KeyCode)102, true))
			{
				Focus();
			}
		}

		private static void Focus()
		{
			if (s_activateInputField == null)
			{
				s_activateInputField = ((object)s_field).GetType().GetMethod("ActivateInputField", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null) ?? AccessTools.Method(typeof(TMP_InputField), "ActivateInputField", (Type[])null, (Type[])null);
			}
			s_activateInputField.Invoke(s_field, null);
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		[HarmonyPostfix]
		private static void Show_Postfix(InventoryGui __instance)
		{
			if (!Enabled)
			{
				if ((Object)(object)s_field != (Object)null)
				{
					((Component)s_field).gameObject.SetActive(false);
				}
				return;
			}
			if ((Object)(object)s_field == (Object)null)
			{
				Create(__instance);
			}
			if ((Object)(object)s_field != (Object)null)
			{
				((Component)s_field).gameObject.SetActive(true);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		[HarmonyPostfix]
		private static void Hide_Postfix()
		{
			if (!((Object)(object)s_field == (Object)null) && (s_words.Length != 0 || s_field.isFocused))
			{
				s_field.DeactivateInputField(false);
				s_field.SetTextWithoutNotify("");
				SetTerm("");
				if ((Object)(object)s_clearButton != (Object)null)
				{
					s_clearButton.SetActive(false);
				}
			}
		}

		private static void Create(InventoryGui gui)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0187: 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_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Expected O, but got Unknown
			//IL_0281: 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)
			TMP_InputField val = (TMP_InputField)(((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				if (!s_warnedMissingSource)
				{
					s_warnedMissingSource = true;
					GlorpheimPlugin.Log.LogWarning((object)"RecipeSearch: the build menu search field was not found, the recipe search box is unavailable");
				}
				return;
			}
			RectTransform component = ((Component)gui.m_tabUpgrade).GetComponent<RectTransform>();
			Transform parent = ((Transform)component).parent;
			RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).GetComponent<LayoutGroup>() != (Object)null)
			{
				Transform obj = (((Object)(object)val2 != (Object)null) ? ((Transform)val2).parent : ((Transform)component).parent);
				val2 = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				GameObject obj2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)val2, false);
				((Object)obj2).name = "glorpheim_RecipeSearch";
				obj2.SetActive(true);
				s_field = obj2.GetComponent<TMP_InputField>();
				s_field.onValueChanged = new OnChangeEvent();
				s_field.onEndEdit = new SubmitEvent();
				s_field.onSubmit = new SubmitEvent();
				s_field.onSelect = new SelectionEvent();
				s_field.onDeselect = new SelectionEvent();
				Traverse.Create((object)s_field).Field("OnInputSubmit").SetValue((object)null);
				s_field.SetTextWithoutNotify("");
				s_field.lineType = (LineType)0;
				s_field.characterLimit = 40;
				s_field.restoreOriginalTextOnEscape = false;
				TMP_InputField obj3 = s_field;
				Navigation navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)0;
				((Selectable)obj3).navigation = navigation;
				((UnityEvent<string>)(object)s_field.onValueChanged).AddListener((UnityAction<string>)OnTextChanged);
				((UnityEvent<string>)(object)s_field.onEndEdit).AddListener((UnityAction<string>)delegate
				{
					s_blockUntilFrame = Time.frameCount;
				});
				((UnityEvent<string>)(object)s_field.onDeselect).AddListener((UnityAction<string>)delegate
				{
					s_blockUntilFrame = Time.frameCount;
				});
				Graphic placeholder = s_field.placeholder;
				TMP_Text val3 = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
				if (val3 != null && string.IsNullOrEmpty(val3.text))
				{
					val3.text = "Search...";
				}
				RectTransform val4 = (RectTransform)obj2.transform;
				float height = Layout(gui, component, val2, val4);
				CreateClearButton(gui, val4, height);
				GlorpheimPlugin.Log.LogDebug((object)$"RecipeSearch: box under '{((Object)val2).name}' at {val4.anchoredPosition}, size {val4.sizeDelta}");
			}
		}

		private static float Layout(InventoryGui gui, RectTransform tab, RectTransform parent, RectTransform rect)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = LocalCorner(parent, tab, 2);
			Vector2 val2 = LocalCorner(parent, tab, 3);
			float num = Mathf.Min(val.y - val2.y, 36f);
			float num2 = (val.y + val2.y) * 0.5f;
			float num3 = val.x + 8f;
			Rect rect2 = parent.rect;
			float num4 = ((Rect)(ref rect2)).xMax - 8f;
			RectTransform[] array = new RectTransform[2];
			Image craftingStationIcon = gui.m_craftingStationIcon;
			array[0] = ((craftingStationIcon != null) ? ((Graphic)craftingStationIcon).rectTransform : null);
			TMP_Text craftingStationName = gui.m_craftingStationName;
			array[1] = ((craftingStationName != null) ? craftingStationName.rectTransform : null);
			RectTransform[] array2 = (RectTransform[])(object)array;
			foreach (RectTransform val3 in array2)
			{
				if (!((Object)(object)val3 == (Object)null))
				{
					float x = LocalCorner(parent, val3, 1).x;
					if (x > num3 + 120f)
					{
						num4 = Mathf.Min(num4, x - 8f);
					}
				}
			}
			float num5 = Mathf.Clamp(num4 - num3, 120f, 320f);
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(0f, 1f);
			rect.anchorMax = val4;
			rect.anchorMin = val4;
			rect.pivot = new Vector2(0f, 1f);
			rect2 = parent.rect;
			float num6 = num3 - ((Rect)(ref rect2)).xMin;
			float num7 = num2 + num * 0.5f;
			rect2 = parent.rect;
			rect.anchoredPosition = new Vector2(num6, num7 - ((Rect)(ref rect2)).yMax);
			rect.sizeDelta = new Vector2(num5, num);
			((Transform)rect).localScale = Vector3.one;
			return num;
		}

		private static Vector2 LocalCorner(RectTransform space, RectTransform target, int corner)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			target.GetWorldCorners(array);
			return Vector2.op_Implicit(((Transform)space).InverseTransformPoint(array[corner]));
		}

		private static void CreateClearButton(InventoryGui gui, RectTransform field, float height)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("ClearButton", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent((Transform)(object)field, false);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(1f, 0.5f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(1f, 0.5f);
			val2.anchoredPosition = new Vector2(-2f, 0f);
			val2.sizeDelta = new Vector2(height, height);
			((Graphic)val.GetComponent<Image>()).color = Color.clear;
			GameObject val4 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			RectTransform val5 = (RectTransform)val4.transform;
			((Transform)val5).SetParent((Transform)(object)val2, false);
			val5.anchorMin = Vector2.zero;
			val5.anchorMax = Vector2.one;
			val3 = (val5.offsetMin = (val5.offsetMax = Vector2.zero));
			TextMeshProUGUI val7 = val4.AddComponent<TextMeshProUGUI>();
			TMP_Text componentInChildren = ((Component)gui.m_tabCraft).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)val7).font = componentInChildren.font;
				((TMP_Text)val7).fontSharedMaterial = componentInChildren.fontSharedMaterial;
				((TMP_Text)val7).fontSize = componentInChildren.fontSize;
			}
			((TMP_Text)val7).text = "X";
			((TMP_Text)val7).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val7).enableAutoSizing = true;
			((TMP_Text)val7).fontSizeMin = 8f;
			((TMP_Text)val7).fontSizeMax = height * 0.7f;
			((Graphic)val7).raycastTarget = false;
			Button component = val.GetComponent<Button>();
			((Selectable)component).targetGraphic = (Graphic)(object)val7;
			ColorBlock colors = ((Selectable)component).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(0.8f, 0.78f, 0.7f, 1f);
			((ColorBlock)(ref colors)).highlightedColor = Color.white;
			((ColorBlock)(ref colors)).pressedColor = new Color(0.6f, 0.6f, 0.6f, 1f);
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((Selectable)component).colors = colors;
			ButtonClickedEvent onClick = component.onClick;
			object obj = <>O.<1>__OnClearPressed;
			if (obj == null)
			{
				UnityAction val8 = OnClearPressed;
				<>O.<1>__OnClearPressed = val8;
				obj = (object)val8;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			RectTransform textViewport = s_field.textViewport;
			if ((Object)(object)textViewport != (Object)null)
			{
				textViewport.offsetMax = new Vector2(Mathf.Min(textViewport.offsetMax.x, 0f - (height + 2f)), textViewport.offsetMax.y);
			}
			s_clearButton = val;
			s_clearButton.SetActive(false);
		}

		private static void OnTextChanged(string text)
		{
			SetTerm(text);
			if ((Object)(object)s_clearButton != (Object)null)
			{
				s_clearButton.SetActive(s_words.Length != 0);
			}
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null) && InventoryGui.IsVisible() && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				UpdateCraftingPanel(instance, arg2: false);
				if ((Object)(object)instance.m_recipeListScroll != (Object)null)
				{
					instance.m_recipeListScroll.value = 1f;
				}
			}
		}

		private static void OnClearPressed()
		{
			if (!((Object)(object)s_field == (Object)null))
			{
				s_field.DeactivateInputField(false);
				s_field.text = "";
			}
		}
	}
	[HarmonyPatch]
	internal static class RequireMod
	{
		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(ZNet __instance)
		{
			GlorpheimPlugin.Cfg.Sync.ModRequired = GlorpheimPlugin.Cfg.RequireMod.Value && __instance.IsServer();
		}
	}
	[HarmonyPatch(typeof(Game), "UpdateSleeping")]
	internal static class SleepWithFewer
	{
		private const double SleepCooldownSeconds = 10.0;

		private static readonly FieldRef<Game, bool> SleepingRef = AccessTools.FieldRefAccess<Game, bool>("m_sleeping");

		private static readonly FieldRef<Game, double> LastSleepTimeRef = AccessTools.FieldRefAccess<Game, double>("m_lastSleepTime");

		private static readonly List<long> s_sleepers = new List<long>();

		[HarmonyPrefix]
		private static bool Prefix(Game __instance)
		{
			if (!GlorpheimPlugin.Cfg.SleepWithFewerEnabled.Value)
			{
				return true;
			}
			if (!ZNet.instance.IsServer())
			{
				return false;
			}
			ref bool reference = ref SleepingRef.Invoke(__instance);
			ref double reference2 = ref LastSleepTimeRef.Invoke(__instance);
			if (reference)
			{
				if (!EnvMan.instance.IsTimeSkipping() && !CinematicsManager.IsPlaying())
				{
					reference2 = ZNet.instance.GetTimeSeconds();
					reference = false;
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStop", Array.Empty<object>());
				}
				return false;
			}
			if (EnvMan.instance.IsTimeSkipping() || (!EnvMan.IsAfternoon() && !EnvMan.IsNight()) || ZNet.instance.GetTimeSeconds() - reference2 < 10.0 || !EnoughPlayersInBed())
			{
				return false;
			}
			EnvMan.instance.SkipToMorning();
			reference = true;
			foreach (long s_sleeper in s_sleepers)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(s_sleeper, "SleepStart", Array.Empty<object>());
			}
			return false;
		}

		private static bool EnoughPlayersInBed()
		{
			s_sleepers.Clear();
			List<ZDO> allCharacterZDOS = ZNet.instance.GetAllCharacterZDOS();
			if (allCharacterZDOS.Count == 0)
			{
				return false;
			}
			foreach (ZDO item in allCharacterZDOS)
			{
				if (item.GetBool(ZDOVars.s_inBed, false))
				{
					s_sleepers.Add(item.GetOwner());
				}
			}
			int num = Mathf.Clamp(GlorpheimPlugin.Cfg.SleepWithFewerRequiredSleepers.Value, 1, allCharacterZDOS.Count);
			return s_sleepers.Count >= num;
		}
	}
	[HarmonyPatch]
	internal static class StationStorage
	{
		[HarmonyPatch]
		private static class ScaledCapacity
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Smelter), "CanUseItems", (Type[])null, (Type[])null);
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				foreach (CodeInstruction instruction in instructions)
				{
					if (CodeInstructionExtensions.LoadsField(instruction, MaxOreField, false))
					{
						yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StationStorage), "MaxOre", (Type[])null, (Type[])null)), instruction);
					}
					else if (CodeInstructionExtensions.LoadsField(instruction, MaxFuelField, false))
					{
						yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StationStorage), "MaxFuel", (Type[])null, (Type[])null)), instruction);
					}
					else
					{
						yield return instruction;
					}
				}
			}
		}

		[HarmonyPatch]
		private static class ScaledHover
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return AccessTools.Method(typeof(Smelter), "OnHoverAddOre", (Type[])null, (Type[])null);
				yield return AccessTools.Method(typeof(Smelter), "OnHoverAddFuel", (Type[])null, (Type[])null);
			}

			[HarmonyPriority(800)]
			private static void Prefix(Smelter __instance, out int[] __state)
			{
				__state = new int[2] { __instance.m_maxOre, __instance.m_maxFuel };
				__instance.m_maxOre = MaxOre(__instance);
				__instance.m_maxFuel = MaxFuel(__instance);
			}

			private static void Finalizer(Smelter __instance, int[] __state)
			{
				if (__state != null)
				{
					__instance.m_maxOre = __state[0];
					__instance.m_maxFuel = __state[1];
				}
			}
		}

		private static readonly FieldInfo MaxOreField = AccessTools.Field(typeof(Smelter), "m_maxOre");

		private static readonly FieldInfo MaxFuelField = AccessTools.Field(typeof(Smelter), "m_maxFuel");

		private static readonly Func<Smelter, int> GetQueueSize = AccessTools.MethodDelegate<Func<Smelter, int>>(AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Smelter, float> GetFuel = AccessTools.MethodDelegate<Func<Smelter, float>>(AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Smelter, Inventory, ItemData> FindCookableItem = AccessTools.MethodDelegate<Func<Smelter, Inventory, ItemData>>(AccessTools.Method(typeof(Smelter), "FindCookableItem", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Smelter, Switch, Humanoid, ItemData, bool> OnAddOre = AccessTools.MethodDelegate<Func<Smelter, Switch, Humanoid, ItemData, bool>>(AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Smelter, Switch, Humanoid, ItemData, bool> OnAddFuel = AccessTools.MethodDelegate<Func<Smelter, Switch, Humanoid, ItemData, bool>>(AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null), (object)null, true);

		private const int ShiftAddAmount = 10;

		private static bool _batching;

		private static bool _holdRepeat;

		private static int CapacityMultiplier()
		{
			if (!GlorpheimPlugin.Cfg.StationStorageEnabled.Value)
			{
				return 1;
			}
			return Math.Max(1, GlorpheimPlugin.Cfg.StationStorageCapacityMultiplier.Value);
		}

		private static int MaxOre(Smelter smelter)
		{
			return smelter.m_maxOre * CapacityMultiplier();
		}

		private static int MaxFuel(Smelter smelter)
		{
			return smelter.m_maxFuel * CapacityMultiplier();
		}

		private static int BatchSize(Humanoid user)
		{
			if (_batching || !GlorpheimPlugin.Cfg.StationStorageEnabled.Value || (Object)(object)user == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return 1;
			}
			if (!ZInput.GetKey((KeyCode)304, true) && !ZInput.GetKey((KeyCode)303, true))
			{
				return 1;
			}
			return 10;
		}

		[HarmonyPatch(typeof(Switch), "Interact")]
		[HarmonyPrefix]
		private static void Switch_Interact_Prefix(bool hold)
		{
			_holdRepeat = hold;
		}

		[HarmonyPatch(typeof(Switch), "Interact")]
		[HarmonyFinalizer]
		private static void Switch_Interact_Finalizer()
		{
			_holdRepeat = false;
		}

		[HarmonyPatch(typeof(Smelter), "OnAddOre")]
		[HarmonyPrefix]
		private static bool Smelter_OnAddOre_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
		{
			int num = BatchSize(user);
			if (num <= 1)
			{
				return true;
			}
			if (_holdRepeat)
			{
				__result = false;
				return false;
			}
			int num2 = MaxOre(__instance) - GetQueueSize(__instance);
			if (num2 <= 0)
			{
				return true;
			}
			Inventory inventory = user.GetInventory();
			ItemData val = item ?? FindCookableItem(__instance, inventory);
			int i = 0;
			string text = null;
			_batching = true;
			try
			{
				for (; i < num && i < num2; i++)
				{
					if (val == null || !inventory.ContainsItem(val))
					{
						val = ((item != null) ? inventory.GetItem(item.m_shared.m_name, -1, false) : FindCookableItem(__instance, inventory));
					}
					if (i > 0 && val == null)
					{
						break;
					}
					string text2 = val?.m_shared.m_name;
					if (!OnAddOre(__instance, sw, user, val))
					{
						break;
					}
					text = text2;
				}
			}
			finally
			{
				_batching = false;
			}
			if (i > 1 && text != null)
			{
				((Character)user).Message((MessageType)2, $"$msg_added {text} x{i}", 0, (Sprite)null, false);
			}
			__result = i > 0;
			return false;
		}

		[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
		[HarmonyPrefix]
		private static bool Smelter_OnAddFuel_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
		{
			int num = BatchSize(user);
			if (num <= 1)
			{
				return true;
			}
			if (_holdRepeat)
			{
				__result = false;
				return false;
			}
			int num2 = Mathf.FloorToInt((float)MaxFuel(__instance) - GetFuel(__instance));
			if (num2 <= 0)
			{
				return true;
			}
			int i = 0;
			_batching = true;
			try
			{
				for (; i < num && i < num2; i++)
				{
					if (!OnAddFuel(__instance, sw, user, item))
					{
						break;
					}
				}
			}
			finally
			{
				_batching = false;
			}
			if (i > 1)
			{
				((Character)user).Message((MessageType)2, $"$msg_added {__instance.m_fuelItem.m_itemData.m_shared.m_name} x{i}", 0, (Sprite)null, false);
			}
			__result = i > 0;
			return false;
		}

		[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Smelter_OnHoverAddOre_Postfix(Smelter __instance, ref string __result)
		{
			AppendHint(ref __result, __instance.m_addOreTooltip);
		}

		[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Smelter_OnHoverAddFuel_Postfix(Smelter __instance, ref string __result)
		{
			AppendHint(ref __result, "$piece_smelter_add " + __instance.m_fuelItem.m_itemData.m_shared.m_name);
		}

		private static void AppendHint(ref string text, string action)
		{
			if (GlorpheimPlugin.Cfg.StationStorageEnabled.Value && !ZInput.GamepadActive && Localization.instance != null)
			{
				string text2 = Localization.instance.Localize(action);
				string text3 = Localization.instance.Localize($"[<b><color=yellow>$button_lshift</color> + <color=yellow>$KEY_Use</color></b>] {text2} (x{10})");
				int num = (string.IsNullOrEmpty(text2) ? (-1) : text.IndexOf(text2, StringComparison.Ordinal));
				if (num < 0)
				{
					text = text + "\n" + text3;
					return;
				}
				int num2 = text.IndexOf('\n', num);
				text = ((num2 < 0) ? (text + "\n" + text3) : text.Insert(num2, "\n" + text3));
			}
		}
	}
}
namespace Glorpheim.Features.PortalHarpoon
{
	internal static class CreatureCapsule
	{
		private const string KeyPrefab = "glorpheim.portalharpoon.prefab";

		private const string KeyData = "glorpheim.portalharpoon.zdo";

		private const string KeyName = "glorpheim.portalharpoon.name";

		private const string KeyLevel = "glorpheim.portalharpoon.level";

		internal static bool IsLoaded(ItemData item)
		{
			return item?.m_customData.ContainsKey("glorpheim.portalharpoon.zdo") ?? false;
		}

		internal static string Describe(ItemData item)
		{
			if (!IsLoaded(item))
			{
				return null;
			}
			item.m_customData.TryGetValue("glorpheim.portalharpoon.name", out var value);
			item.m_customData.TryGetValue("glorpheim.portalharpoon.level", out var value2);
			int.TryParse(value2, out var result);
			StringBuilder stringBuilder = new StringBuilder(Localization.instance.Localize(value ?? "?"));
			for (int i = 1; i < result; i++)
			{
				stringBuilder.Append(" ★");
			}
			return stringBuilder.ToString();
		}

		internal static bool Capture(ItemData item, Character creature)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			ZNetView component = ((Component)creature).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return false;
			}
			ZDO zDO = component.GetZDO();
			ZPackage val = new ZPackage();
			zDO.Serialize(val);
			Tameable component2 = ((Component)creature).GetComponent<Tameable>();
			item.m_customData["glorpheim.portalharpoon.prefab"] = Utils.GetPrefabName(((Component)creature).gameObject);
			item.m_customData["glorpheim.portalharpoon.zdo"] = val.GetBase64();
			item.m_customData["glorpheim.portalharpoon.name"] = (((Object)(object)component2 != (Object)null) ? component2.GetHoverName() : creature.m_name);
			item.m_customData["glorpheim.portalharpoon.level"] = creature.GetLevel().ToString();
			component.ClaimOwnership();
			ZNetScene.instance.Destroy(((Component)creature).gameObject);
			return true;
		}

		internal static GameObject Release(ItemData item, Vector3 position, Quaternion rotation)
		{
			//IL_005f: 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)
			//IL_0087: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (!IsLoaded(item))
			{
				return null;
			}
			item.m_customData.TryGetValue("glorpheim.portalharpoon.prefab", out var value);
			GameObject val = (string.IsNullOrEmpty(value) ? null : ZNetScene.instance.GetPrefab(value));
			if ((Object)(object)val == (Object)null)
			{
				GlorpheimPlugin.Log.LogWarning((object)("PortalHarpoon: stored creature prefab '" + value + "' does not exist"));
				return null;
			}
			ZDO val2;
			try
			{
				val2 = ZDOMan.instance.CreateNewZDO(position, StringExtensionMethods.GetStableHashCode(value));
				val2.Deserialize(new ZPackage(item.m_customData["glorpheim.portalharpoon.zdo"]));
			}
			catch (Exception arg)
			{
				GlorpheimPlugin.Log.LogError((object)$"PortalHarpoon: could not restore stored creature: {arg}");
				return null;
			}
			val2.SetPosition(position);
			val2.SetRotation(rotation);
			uint dataRevision = val2.DataRevision;
			val2.DataRevision = dataRevision + 1;
			ZNetView.m_useInitZDO = true;
			ZNetView.m_initZDO = val2;
			GameObject result;
			try
			{
				result = Object.Instantiate<GameObject>(val, position, rotation);
			}
			finally
			{
				ZNetView.m_initZDO = null;
				ZNetView.m_useInitZDO = false;
			}
			Clear(item);
			return result;
		}

		internal static void Clear(ItemData item)
		{
			item.m_customData.Remove("glorpheim.portalharpoon.prefab");
			item.m_customData.Remove("glorpheim.portalharpoon.zdo");
			item.m_customData.Remove("glorpheim.portalharpoon.name");
			item.m_customData.Remove("glorpheim.portalharpoon.level");
		}
	}
	[HarmonyPatch]
	internal static class PortalHarpoonFeature
	{
		private static readonly int ReleaseRayMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle" });

		private static bool Enabled => PortalHarpoonItem.Enabled;

		[HarmonyPatch(typeof(Projectile), "OnHit")]
		[HarmonyPrefix]
		private static bool Projectile_OnHit_Prefix(Projectile __instance, Collider collider, Vector3 hitPoint, Character ___m_owner, ItemData ___m_weapon)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled && !((Object)(object)collider == (Object)null))
			{
				Player val = (Player)(object)((___m_owner is Player) ? ___m_owner : null);
				if (val != null && PortalHarpoonItem.IsPortalHarpoon(___m_weapon))
				{
					GameObject val2 = Projectile.FindHitObject(collider);
					Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Character>() : null);
					Tameable val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Tameable>() : null);
					if ((Object)(object)val4 == (Object)null || val3.IsPlayer() || val3.IsBoss() || val3.IsDead())
					{
						return true;
					}
					if (CreatureCapsule.IsLoaded(___m_weapon))
					{
						((Character)val).Message((MessageType)2, "$msg_portalharpoon_full", 0, (Sprite)null, false);
						return true;
					}
					string hoverName = val4.GetHoverName();
					if (!CreatureCapsule.Capture(___m_weapon, val3))
					{
						return true;
					}
					((Character)val).Message((MessageType)2, hoverName + " $msg_portalharpoon_captured", 0, (Sprite)null, false);
					__instance.m_hitEffects.Create(hitPoint, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
					ZNetScene.instance.Destroy(((Component)__instance).gameObject);
					return false;
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(Player), "SetControls")]
		[HarmonyPrefix]
		private static void Player_SetControls_Prefix(Player __instance, ref bool block, ref bool blockHold)
		{
			if (!Enabled || !block || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
			if (PortalHarpoonItem.IsPortalHarpoon(currentWeapon) && CreatureCapsule.IsLoaded(currentWeapon))
			{
				block = false;
				blockHold = false;
				if (!((Character)__instance).IsDead() && !((Character)__instance).IsTeleporting() && !((Character)__instance).IsAttached() && !((Character)__instance).InPlaceMode() && !((Character)__instance).InAttack())
				{
					TryRelease(__instance, currentWeapon);
				}
			}
		}

		private static void TryRelease(Player player, ItemData weapon)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_00a4: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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)
			GameCamera instance = GameCamera.instance;
			RaycastHit val = default(RaycastHit);
			if ((Object)(object)instance == (Object)null || !Physics.Raycast(((Component)instance).transform.position, ((Component)instance).transform.forward, ref val, 1000f, ReleaseRayMask))
			{
				((Character)player).Message((MessageType)2, "$msg_portalharpoon_nospot", 0, (Sprite)null, false);
				return;
			}
			Vector3 val2 = ((RaycastHit)(ref val)).point + Vector3.up * 0.1f;
			Vector3 val3 = ((Component)player).transform.position - val2;
			val3.y = 0f;
			Quaternion rotation = ((((Vector3)(ref val3)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(((Vector3)(ref val3)).normalized) : ((Component)player).transform.rotation);
			string text = CreatureCapsule.Describe(weapon);
			if ((Object)(object)CreatureCapsule.Release(weapon, val2, rotation) != (Object)null)
			{
				((Character)player).Message((MessageType)2, text + " $msg_portalharpoon_released", 0, (Sprite)null, false);
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		})]
		[HarmonyPostfix]
		private static void ItemData_GetTooltip_Postfix(ItemData item, bool crafting, ref string __result)
		{
			if (!(!Enabled || crafting) && PortalHarpoonItem.IsPortalHarpoon(item))
			{
				string text = CreatureCapsule.Describe(item);
				string text2 = ((text != null) ? ("<color=#7fd67f>" + Localization.instance.Localize("$item_portalharpoon_holds") + ": " + text + "</color>") : ("<color=#9a9a9a>" + Localization.instance.Localize("$item_portalharpoon_empty") + "</color>"));
				__result = __result + "\n\n" + text2;
			}
		}
	}
	[HarmonyPatch]
	internal static class PortalHarpoonItem
	{
		internal const string PrefabName = "PortalHarpoon";

		internal const string ItemName = "$item_portalharpoon";

		private const string SourcePrefab = "SpearChitin";

		private const string WorkbenchPrefab = "piece_workbench";

		private static readonly Color IconTint = new Color(0.35f, 0.7f, 0.35f);

		private static readonly Dictionary<string, string> Words = new Dictionary<string, string>
		{
			["item_portalharpoon"] = "Portal Harpoon",
			["item_portalharpoon_description"] = "An Abyssal Harpoon threaded with surtling fire and greydwarf sight. A tameable creature it strikes is pulled inside; right click to set it down somewhere else. Stars, taming and name survive the trip.",
			["item_portalharpoon_holds"] = "Holds",
			["item_portalharpoon_empty"] = "Empty. Hit a tameable creature to store it.",
			["msg_portalharpoon_captured"] = "stored in the harpoon",
			["msg_portalharpoon_released"] = "released",
			["msg_portalharpoon_full"] = "The harpoon already holds a creature",
			["msg_portalharpoon_nospot"] = "Nowhere to release the creature there"
		};

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

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

		private static GameObject s_holder;

		private static GameObject s_prefab;

		private static Recipe s_recipe;

		internal static bool Enabled => GlorpheimPlugin.Cfg.PortalHarpoonEnabled.Value;

		internal static bool IsPortalHarpoon(ItemData item)
		{
			if (item != null && item.m_shared != null)
			{
				return item.m_shared.m_name == "$item_portalharpoon";
			}
			return false;
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		[HarmonyPostfix]
		private static void ObjectDB_Awake_Postfix(ObjectDB __instance)
		{
			if (Enabled)
			{
				Register(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		[HarmonyPostfix]
		private static void ObjectDB_CopyOtherDB_Postfix(ObjectDB __instance)
		{
			if (Enabled)
			{
				Register(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPrefix]
		private static void ZNetScene_Awake_Prefix(ZNetScene __instance)
		{
			if (Enabled && !((Object)(object)s_prefab == (Object)null) && !__instance.m_prefabs.Contains(s_prefab))
			{
				__instance.m_prefabs.Add(s_prefab);
			}
		}

		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		[HarmonyPostfix]
		private static void Localization_SetupLanguage_Postfix(Localization __instance)
		{
			if (Enabled)
			{
				AddWords(__instance);
			}
		}

		private static void Register(ObjectDB db)
		{
			if (db.m_items.Count != 0 && (!((Object)(object)s_prefab == (Object)null) || CreatePrefab(db)))
			{
				bool flag = false;
				if (!db.m_items.Contains(s_prefab))
				{
					db.m_items.Add(s_prefab);
					flag = true;
				}
				if ((Object)(object)s_recipe == (Object)null)
				{
					s_recipe = CreateRecipe(db);
				}
				if ((Object)(object)s_recipe != (Object)null && !db.m_recipes.Contains(s_recipe))
				{
					db.m_recipes.Add(s_recipe);
				}
				if (flag)
				{
					UpdateRegisters.Invoke(db, null);
				}
				if (Localization.instance != null)
				{
					AddWords(Localization.instance);
				}
			}
		}

		private static bool CreatePrefab(ObjectDB db)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			GameObject itemPrefab = db.GetItemPrefab("SpearChitin");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				GlorpheimPlugin.Log.LogWarning((object)"PortalHarpoon: item prefab 'SpearChitin' not found, item not added");
				return false;
			}
			s_holder = new GameObject("glorpheim_prefabs");
			s_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)s_holder);
			s_prefab = Object.Instantiate<GameObject>(itemPrefab, s_holder.transform);
			((Object)s_prefab).name = "PortalHarpoon";
			SharedData shared = s_prefab.GetComponent<ItemDrop>().m_itemData.m_shared;
			shared.m_name = "$item_portalharpoon";
			shared.m_description = "$item_portalharpoon_description";
			Sprite[] array = (Sprite[])(object)new Sprite[shared.m_icons.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = shared.m_icons[i];
				try
				{
					array[i] = TintSprite(shared.m_icons[i], IconTint) ?? shared.m_icons[i];
				}
				catch (Exception ex)
				{
					GlorpheimPlugin.Log.LogWarning((object)("PortalHarpoon: could not tint icon, using the Abyssal Harpoon one: " + ex.Message));
				}
			}
			shared.m_icons = array;
			return true;
		}

		private static Recipe CreateRecipe(ObjectDB db)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00e9: Expected O, but got Unknown
			//IL_00eb: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			ItemDrop item = GetItem(db, "SpearChitin");
			ItemDrop item2 = GetItem(db, "GreydwarfEye");
			ItemDrop item3 = GetItem(db, "SurtlingCore");
			if ((Object)(object)item == (Object)null || (Object)(object)item2 == (Object)null || (Object)(object)item3 == (Object)null)
			{
				GlorpheimPlugin.Log.LogWarning((object)"PortalHarpoon: recipe ingredients missing, item cannot be crafted");
				return null;
			}
			CraftingStation val = FindStation(db, "piece_workbench") ?? db.GetRecipe(item.m_itemData)?.m_craftingStation;
			Recipe val2 = ScriptableObject.CreateInstance<Recipe>();
			((Object)val2).name = "Recipe_PortalHarpoon";
			val2.m_item = s_prefab.GetComponent<ItemDrop>();
			val2.m_amount = 1;
			val2.m_enabled = true;
			val2.m_craftingStation = val;
			val2.m_repairStation = val;
			val2.m_minStationLevel = 1;
			val2.m_resources = (Requirement[])(object)new Requirement[3]
			{
				new Requirement
				{
					m_resItem = item,
					m_amount = 1,
					m_amountPerLevel = 0
				},
				new Requirement
				{
					m_resItem = item2,
					m_amount = 20,
					m_amountPerLevel = 10
				},
				new Requirement
				{
					m_resItem = item3,
					m_amount = 5,
					m_amountPerLevel = 2
				}
			};
			return val2;
		}

		private static ItemDrop GetItem(ObjectDB db, string prefabName)
		{
			GameObject itemPrefab = db.GetItemPrefab(prefabName);
			if (!((Object)(object)itemPrefab != (Object)null))
			{
				return null;
			}
			return itemPrefab.GetComponent<ItemDrop>();
		}

		private static CraftingStation FindStation(ObjectDB db, string prefabName)
		{
			foreach (Recipe recipe in db.m_recipes)
			{
				CraftingStation craftingStation = recipe.m_craftingStation;
				if ((Object)(object)craftingStation != (Object)null && ((Object)craftingStation).name == prefabName)
				{
					return craftingStation;
				}
			}
			return null;
		}

		private static void AddWords(Localization localization)
		{
			foreach (KeyValuePair<string, string> word in Words)
			{
				AddWord.Invoke(localization, new object[2] { word.Key, word.Value });
			}
		}

		private static Sprite TintSprite(Sprite sprite, Color tint)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null || (int)SystemInfo.graphicsDeviceType == 4)
			{
				return null;
			}
			Texture2D texture = sprite.texture;
			Rect textureRect = sprite.textureRect;
			int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
			int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
			if (num <= 0 || num2 <= 0)
			{
				return null;
			}
			RenderTexture active = RenderTexture.active;
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			Texture2D val;
			try
			{
				Graphics.Blit((Texture)(object)texture, temporary);
				RenderTexture.active = temporary;
				val = new Texture2D(num, num2, (TextureFormat)4, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
			Color[] pixels = val.GetPixels();
			for (int i = 0; i < pixels.Length; i++)
			{
				Color val2 = pixels[i];
				pixels[i] = new Color(val2.r * tint.r, val2.g * tint.g, val2.b * tint.b, val2.a);
			}
			val.SetPixels(pixels);
			val.Apply();
			((Object)val).name = ((Object)sprite.texture).name + "_portal";
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), sprite.pixelsPerUnit);
			((Object)obj).name = ((Object)sprite).name + "_portal";
			return obj;
		}
	}
}
namespace Glorpheim.Features.ItemLink
{
	[HarmonyPatch]
	internal static class ChatCursor
	{
		private static bool Enabled => GlorpheimPlugin.Cfg.ItemLinkEnabled.Value;

		private static bool ChatFocused
		{
			get
			{
				if ((Object)(object)Chat.instance != (Object)null)
				{
					return Chat.instance.HasFocus();
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		[HarmonyPostfix]
		private static void GameCamera_UpdateMouseCapture_Postfix()
		{
			if (Enabled && ChatFocused)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
			}
		}

		[HarmonyPatch(typeof(ZInput), "TryGetKeyStateLowLevel")]
		[HarmonyPrefix]
		private static bool ZInput_TryGetKeyStateLowLevel_Prefix(KeyCode keyCode, ref bool __result)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if (!Enabled || (int)keyCode != 323 || !ChatFocused || !PointerOverChat())
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool PointerOverChat()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Chat instance = Chat.instance;
			RectTransform val = (((Object)(object)instance != (Object)null) ? ((Terminal)instance).m_chatWindow : null);
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
			{
				return false;
			}
			Canvas componentInParent = ((Component)val).GetComponentInParent<Canvas>();
			Camera val2 = (((Object)(object)componentInParent == (Object)null || (int)componentInParent.renderMode == 0) ? null : componentInParent.worldCamera);
			return RectTransformUtility.RectangleContainsScreenPoint(val, Vector2.op_Implicit(ZInput.pointerPosition), val2);
		}
	}
	[HarmonyPatch]
	internal static class ChatLinks
	{
		private sealed class Pending
		{
			public long Sender;

			public List<(string Label, ItemData Item)> Links;

			public float ArrivedAt;
		}

		private const string LinkPrefix = "glorpheim:";

		private const string LinkColor = "#8FD3FF";

		private const float PendingSeconds = 15f;

		private const int MaxLinks = 256;

		private const int RetrofitDepth = 10;

		private static readonly FieldRef<Terminal, List<string>> ChatBuffer = AccessTools.FieldRefAccess<Terminal, List<string>>("m_chatBuffer");

		private static readonly Action<Terminal> UpdateChat = AccessTools.MethodDelegate<Action<Terminal>>(AccessTools.Method(typeof(Terminal), "UpdateChat", (Type[])null, (Type[])null), (object)null, true);

		private static readonly List<Pending> s_pending = new List<Pending>();

		private static readonly Dictionary<int, ItemData> s_links = new Dictionary<int, ItemData>();

		private static readonly Queue<int> s_linkOrder = new Queue<int>();

		private static int s_nextId;

		private static readonly Dictionary<PlatformUserID, long> s_senders = new Dictionary<PlatformUserID, long>();

		private static readonly List<(string Line, long Sender)> s_recentLines = new List<(string, long)>();

		private static GameObject s_tooltip;

		private static GameObject s_tooltipPrefab;

		private static Vector3 s_tooltipBodyPosition;

		internal static void Clear()
		{
			s_pending.Clear();
			s_links.Clear();
			s_linkOrder.Clear();
			s_senders.Clear();
			s_recentLines.Clear();
			HideTooltip();
		}

		internal static void Add(long sender, List<(string Label, ItemData Item)> links)
		{
			PrunePending();
			Pending pending = new Pending
			{
				Sender = sender,
				Links = links,
				ArrivedAt = Time.realtimeSinceStartup
			};
			s_pending.Add(pending);
			Retrofit(pending);
		}

		[HarmonyPatch(typeof(Terminal), "AddString", new Type[]
		{
			typeof(PlatformUserID),
			typeof(string),
			typeof(Type),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void Terminal_AddString_Prefix(Terminal __instance, PlatformUserID user, ref string text, out (long Sender, string LastLine) __state)
		{
			/