Decompiled source of Artisan v1.0.2

Artisan.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Artisan.Features.Inventory;
using Artisan.Localization;
using Artisan.Shared.Reflection;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FMODUnity;
using HarmonyLib;
using Mirror;
using Mirror.RemoteCalls;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using YAPYAP;
using YAPYAP.Npc.Shopkeeper;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Artisan")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Artisan")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2295655e-9260-4eae-a7c1-b44cabf62fea")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Artisan
{
	[BepInPlugin("gamedroit.artisan", "Artisan", "1.0.2")]
	public sealed class ArtisanMod : BaseUnityPlugin
	{
		private Harmony harmony;

		public static ConfigEntry<bool> EnableTeleBlastDamagePatch;

		public static ConfigEntry<bool> MakeTeleBlastDamageOtherPlayers;

		public static ConfigEntry<int> TeleBlastSpellDamage;

		public static ConfigEntry<bool> MakeAeroDamageOtherPlayers;

		public static ConfigEntry<bool> EnableAeroDamagePatch;

		public static ConfigEntry<int> AeroSpellDamage;

		public static ConfigEntry<bool> EnableExtendedInventorySlots;

		public static ConfigEntry<int> MaxInventorySlots;

		public static ConfigEntry<bool> EnableInventorySlotUpgrades;

		public static ConfigEntry<int> ExtraSlotBasePrice;

		public static ConfigEntry<float> ExtraSlotPriceMultiplier;

		public static ConfigEntry<bool> EnableShowMonstersHealthBar;

		public static ConfigEntry<bool> EnableShowMonsterDamageIndicator;

		public static ConfigEntry<float> MonsterHealthBarExtraHeightOffset;

		internal static ManualLogSource Logger { get; private set; }

		public void Awake()
		{
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			EnableAeroDamagePatch = ((BaseUnityPlugin)this).Config.Bind<bool>("Aero", "Enable Aero Damage Patch", true, "Enable or disable the damage patch for Aero spell.");
			MakeAeroDamageOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Aero", "Make Aero Damage Other Players", false, "Allow Aero spell to damage other players when the damage patch is enabled.");
			AeroSpellDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Aero", "Aero Spell Damage", 2, "Amount of damage the Aero spell will deal when the damage patch is enabled.");
			EnableTeleBlastDamagePatch = ((BaseUnityPlugin)this).Config.Bind<bool>("TeleBlast", "Enable TeleBlast Damage Patch", true, "Enable or disable the damage patch for TeleBlast spell.");
			MakeTeleBlastDamageOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("TeleBlast", "Make TeleBlast Damage Other Players", false, "Allow TeleBlast spell to damage other players when the damage patch is enabled.");
			TeleBlastSpellDamage = ((BaseUnityPlugin)this).Config.Bind<int>("TeleBlast", "TeleBlast Spell Damage", 5, "Amount of damage the TeleBlast spell will deal when the damage patch is enabled.");
			EnableExtendedInventorySlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "Enable Extended Inventory Slots", true, "Enable or disable increasing the inventory from 3 to 6 slots.");
			MaxInventorySlots = ((BaseUnityPlugin)this).Config.Bind<int>("Inventory", "Max Inventory Slots", 6, "Maximum inventory slots. Vanilla is 3. Recommended value is 6.");
			EnableInventorySlotUpgrades = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "Enable Inventory Slot Upgrades", true, "Enable or disable the ability to upgrade inventory slots. When disabled, all extra slots will be available from the start without needing to purchase them.");
			ExtraSlotBasePrice = ((BaseUnityPlugin)this).Config.Bind<int>("Inventory", "Extra Slot Base Price", 40, "Base price for the first extra inventory slot. Each subsequent slot will cost more based on the multiplier.");
			ExtraSlotPriceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Inventory", "Extra Slot Price Multiplier", 1.5f, "Price multiplier for each additional inventory slot. For example, with a base price of 40 and a multiplier of 1.5, the first extra slot would cost 40, the second would cost 60 (40 * 1.5), the third would cost 90 (60 * 1.5), and so on.");
			EnableShowMonstersHealthBar = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Enable Show Monsters Health Bar", true, "Enable or disable showing monsters' health bars.");
			EnableShowMonsterDamageIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Enable Show Monster Damage Indicator", true, "Enable or disable showing damage indicators on monsters.");
			MonsterHealthBarExtraHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Monster Health Bar Extra Height Offset", 0.45f, "Additional height offset for monster health bars to prevent overlap with the monster's model.");
			if (EnableInventorySlotUpgrades.Value)
			{
				ArtisanText.Add((SystemLanguage)10, "inventory_upgrade_full", "Backpack fully upgraded");
				ArtisanText.Add((SystemLanguage)10, "inventory_upgrade_buy", "(Hold) Upgrade backpack ({0} Gold)");
				ArtisanText.Add((SystemLanguage)28, "inventory_upgrade_full", "Mochila totalmente melhorada");
				ArtisanText.Add((SystemLanguage)28, "inventory_upgrade_buy", "(Segurar) Melhorar mochila ({0} Ouros)");
			}
			harmony = new Harmony("gamedroit.artisan");
			ArtisanInventoryUpgradeNetwork.Register();
			try
			{
				harmony.PatchAll(Assembly.GetExecutingAssembly());
				foreach (MethodBase patchedMethod in harmony.GetPatchedMethods())
				{
					Logger.LogInfo((object)("Patched: " + patchedMethod.DeclaringType?.FullName + "." + patchedMethod.Name));
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Harmony patch failed: {arg}");
			}
			Logger.LogInfo((object)"Artisan mod is loaded and initialized.");
		}

		public void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace Artisan.Shared.Reflection
{
	public static class HarmonyUtil
	{
		public static void CopyMatchingFieldsIncludingBaseTypes(object source, object target)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}
			Type type = source.GetType();
			while (type != null && type != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly)
					{
						FieldInfo fieldInfo2 = FindFieldInHierarchy(target.GetType(), fieldInfo.Name);
						if (!(fieldInfo2 == null) && !fieldInfo2.IsStatic && !fieldInfo2.IsInitOnly && !(fieldInfo2.FieldType != fieldInfo.FieldType))
						{
							fieldInfo2.SetValue(target, fieldInfo.GetValue(source));
						}
					}
				}
				type = type.BaseType;
			}
		}

		private static FieldInfo FindFieldInHierarchy(Type type, string fieldName)
		{
			while (type != null && type != typeof(MonoBehaviour))
			{
				FieldInfo field = type.GetField(fieldName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field;
				}
				type = type.BaseType;
			}
			return null;
		}

		public static void CopySpellConfiguration(Spell source, Spell target)
		{
			HashSet<string> hashSet = new HashSet<string>
			{
				"spellData", "casterPawn", "NetworkcasterIdentity", "currentCharges", "isCasting", "isInitialized", "lastCastTime", "regenerationStartTime", "netIdentity", "syncObjects",
				"syncVarDirtyBits", "connectionToClient", "connectionToServer"
			};
			Type type = ((object)source).GetType();
			while (type != null && type != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !hashSet.Contains(fieldInfo.Name))
					{
						FieldInfo fieldInfo2 = AccessTools.Field(((object)target).GetType(), fieldInfo.Name);
						if (!(fieldInfo2 == null) && !(fieldInfo2.FieldType != fieldInfo.FieldType))
						{
							fieldInfo2.SetValue(target, fieldInfo.GetValue(source));
						}
					}
				}
				type = type.BaseType;
			}
		}

		public static void CopyMatchingFields(object source, object target)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (target == null)
			{
				throw new ArgumentNullException("target");
			}
			Type type = source.GetType();
			Type type2 = target.GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsStatic)
				{
					FieldInfo fieldInfo2 = AccessTools.Field(type2, fieldInfo.Name);
					if (!(fieldInfo2 == null) && !fieldInfo2.IsStatic && !fieldInfo2.IsInitOnly && !(fieldInfo2.FieldType != fieldInfo.FieldType))
					{
						object value = fieldInfo.GetValue(source);
						fieldInfo2.SetValue(target, value);
						ArtisanMod.Logger.LogInfo((object)("Copied field '" + fieldInfo.Name + "' from '" + type.Name + "' to '" + type2.Name + "'."));
					}
				}
			}
		}

		public static void CopySerializedSpellFields(Spell source, Spell target)
		{
			Type type = ((object)source).GetType();
			while (type != null && type != typeof(Spell))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && !(AccessTools.Field(((object)target).GetType(), fieldInfo.Name) == null))
					{
						fieldInfo.SetValue(target, fieldInfo.GetValue(source));
					}
				}
				type = type.BaseType;
			}
		}

		public static void CopySerializedFields<T>(T source, T target) where T : ScriptableObject
		{
			if ((Object)(object)source == (Object)null)
			{
				throw new ArgumentNullException("source");
			}
			if ((Object)(object)target == (Object)null)
			{
				throw new ArgumentNullException("target");
			}
			Type type = typeof(T);
			while (type != null && type != typeof(ScriptableObject))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && !fieldInfo.IsNotSerialized)
					{
						fieldInfo.SetValue(target, fieldInfo.GetValue(source));
					}
				}
				type = type.BaseType;
			}
		}

		public static T GetFieldValue<T>(object instance, string fieldName)
		{
			if (instance == null)
			{
				return default(T);
			}
			FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName);
			if (fieldInfo == null && instance.GetType().BaseType != null)
			{
				fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName);
			}
			if (fieldInfo == null)
			{
				ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'."));
				return default(T);
			}
			object value = fieldInfo.GetValue(instance);
			if (value is T)
			{
				return (T)value;
			}
			return default(T);
		}

		public static void SetFieldValue<T>(object instance, string fieldName, T value)
		{
			if (instance != null)
			{
				FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName);
				if (fieldInfo == null && instance.GetType().BaseType != null)
				{
					fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName);
				}
				if (fieldInfo == null)
				{
					ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'."));
				}
				else
				{
					fieldInfo.SetValue(instance, value);
				}
			}
		}
	}
}
namespace Artisan.Localization
{
	public static class ArtisanLocalization
	{
		internal static IList VoskTranslators;

		internal static object DefaultVoskTranslator;

		internal static VoskLocalisation[] VoskLocalisations;

		internal static bool IsVoskLoaded = false;

		internal static Dictionary<SystemLanguage, object> QueuedTranslations = new Dictionary<SystemLanguage, object>();

		internal static void ProcessQueuedTranslations()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsVoskLoaded)
			{
				return;
			}
			foreach (KeyValuePair<SystemLanguage, object> queuedTranslation in QueuedTranslations)
			{
				if (queuedTranslation.Value is ArtisanVoiceCommand[] voiceCommands)
				{
					AddVoiceCommand(queuedTranslation.Key, voiceCommands);
				}
			}
			QueuedTranslations.Clear();
		}

		public static void AddVoiceCommand(SystemLanguage language, ArtisanVoiceCommand[] voiceCommands)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			if (!IsVoskLoaded)
			{
				ArtisanMod.Logger.LogWarning((object)$"Vosk is not loaded yet. Queuing {voiceCommands.Length} voice commands for language {language} to be added later.");
				QueuedTranslations[language] = voiceCommands;
				return;
			}
			int voskTranslatorIndex = GetVoskTranslatorIndex(language);
			object obj = ((voskTranslatorIndex == -1) ? DefaultVoskTranslator : VoskTranslators[voskTranslatorIndex]);
			if (obj == null)
			{
				ArtisanMod.Logger.LogError((object)$"Failed to find a Vosk translator for language {language}.");
				return;
			}
			Dictionary<string, string[]> fieldValue = HarmonyUtil.GetFieldValue<Dictionary<string, string[]>>(obj, "_commands");
			string[] fieldValue2 = HarmonyUtil.GetFieldValue<string[]>(obj, "_grammar");
			if (fieldValue == null || fieldValue2 == null)
			{
				ArtisanMod.Logger.LogError((object)$"Failed to access the commands or grammar of the Vosk translator for language {language}.");
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(fieldValue2);
			foreach (ArtisanVoiceCommand artisanVoiceCommand in voiceCommands)
			{
				if (fieldValue.ContainsKey(artisanVoiceCommand.Key))
				{
					if (!artisanVoiceCommand.OverwriteExisting)
					{
						ArtisanMod.Logger.LogWarning((object)$"Command for key '{artisanVoiceCommand.Key}' already exists in language {language}. Use overwrite=true to replace it.");
						continue;
					}
					ArtisanMod.Logger.LogWarning((object)$"Overwriting existing command for key '{artisanVoiceCommand.Key}' in language {language}.");
				}
				string[] array = ToCommandWords(artisanVoiceCommand.Command);
				if (array.Length == 0)
				{
					ArtisanMod.Logger.LogWarning((object)$"Command '{artisanVoiceCommand.Command}' for key '{artisanVoiceCommand.Key}' in language {language} does not contain any valid words.");
					continue;
				}
				fieldValue[artisanVoiceCommand.Key] = array;
				string[] array2 = array;
				foreach (string item in array2)
				{
					if (!hashSet.Contains(item))
					{
						hashSet.Add(item);
					}
				}
			}
			HarmonyUtil.SetFieldValue(obj, "_grammar", hashSet.ToArray());
			ArtisanMod.Logger.LogInfo((object)$"Added {voiceCommands.Length} voice commands to language {language}. Total grammar size is now {hashSet.Count}.");
		}

		private static string[] ToCommandWords(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return new string[0];
			}
			return (from word in value.Split(new char[2] { '-', ' ' }, StringSplitOptions.RemoveEmptyEntries)
				select word.Trim() into word
				where !string.IsNullOrEmpty(word)
				select word.ToUpperInvariant()).ToArray();
		}

		private static int GetVoskTranslatorIndex(SystemLanguage language)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			string systemCulture = CultureInfo.CurrentCulture.Name;
			int num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language && l.CultureCode == systemCulture && !l.IsOptional);
			if (num == -1)
			{
				num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language && !l.IsOptional);
			}
			if (num == -1)
			{
				num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language);
			}
			return num;
		}
	}
	[HarmonyPatch(typeof(VoiceManager), "LoadLocalisationData")]
	public static class VoiceLocalizationPatches
	{
		[HarmonyPostfix]
		private static void Postfix(VoiceManager __instance)
		{
			IList fieldValue = HarmonyUtil.GetFieldValue<IList>(__instance, "_voskTranslators");
			object fieldValue2 = HarmonyUtil.GetFieldValue<object>(__instance, "_defaultTranslator");
			VoskLocalisation[] fieldValue3 = HarmonyUtil.GetFieldValue<VoskLocalisation[]>(__instance, "_voskLocalisations");
			ArtisanLocalization.VoskTranslators = fieldValue;
			ArtisanLocalization.VoskLocalisations = fieldValue3;
			ArtisanLocalization.DefaultVoskTranslator = fieldValue2;
			ArtisanMod.Logger.LogInfo((object)$"Loaded {fieldValue.Count} Vosk translators and {fieldValue3.Length} Vosk localisations");
			ArtisanLocalization.IsVoskLoaded = true;
			ArtisanLocalization.ProcessQueuedTranslations();
		}
	}
	public static class ArtisanText
	{
		private static readonly Dictionary<SystemLanguage, Dictionary<string, string>> Translations = new Dictionary<SystemLanguage, Dictionary<string, string>>();

		public static void Add(SystemLanguage language, string key, string value)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!Translations.TryGetValue(language, out var value2))
			{
				value2 = new Dictionary<string, string>();
				Translations[language] = value2;
			}
			value2[key] = value;
		}

		public static string Translate(string key)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			SystemLanguage key2 = (SystemLanguage)10;
			LocalisationManager val = default(LocalisationManager);
			if (Service.Get<LocalisationManager>(ref val) && val.CurrentTranslator != null)
			{
				key2 = val.CurrentTranslator.Language;
			}
			if (Translations.TryGetValue(key2, out var value) && value.TryGetValue(key, out var value2))
			{
				return value2;
			}
			if (Translations.TryGetValue((SystemLanguage)10, out var value3) && value3.TryGetValue(key, out var value4))
			{
				return value4;
			}
			return key;
		}

		public static string Format(string key, params object[] args)
		{
			return string.Format(Translate(key), args);
		}
	}
	public sealed class ArtisanVoiceCommand
	{
		public string Key { get; private set; }

		public string Command { get; private set; }

		public bool OverwriteExisting { get; private set; }

		public ArtisanVoiceCommand(string key, string command, bool overwriteExisting = false)
		{
			Key = key;
			Command = command;
			OverwriteExisting = overwriteExisting;
		}
	}
}
namespace Artisan.Features.Spells
{
	[HarmonyPatch(typeof(ProjectilePush), "OnTargetHit")]
	public class ProjectilePushDamagePatch
	{
		private static readonly Dictionary<int, HashSet<uint>> DamagedTargetsByProjectile = new Dictionary<int, HashSet<uint>>();

		public static void Prefix(ProjectilePush __instance, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity)
		{
			//IL_00a7: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || (Object)(object)__instance == (Object)null || (Object)(object)target == (Object)null || (Object)(object)targetRigidbody == (Object)null || (Object)(object)targetIdentity == (Object)null)
			{
				return;
			}
			bool flag = IsAeroProjectile(__instance);
			bool flag2 = IsLevitationBlastProjectile(__instance);
			if ((!flag && !flag2) || (flag && !ArtisanMod.EnableAeroDamagePatch.Value) || (flag2 && !ArtisanMod.EnableTeleBlastDamagePatch.Value))
			{
				return;
			}
			int num = (flag ? ArtisanMod.AeroSpellDamage.Value : (flag2 ? ArtisanMod.TeleBlastSpellDamage.Value : 0));
			bool flag3 = (flag ? ArtisanMod.MakeAeroDamageOtherPlayers.Value : (flag2 && ArtisanMod.MakeTeleBlastDamageOtherPlayers.Value));
			LayerMask fieldValue = HarmonyUtil.GetFieldValue<LayerMask>(__instance, "pushableLayer");
			if (((1 << ((Component)target).gameObject.layer) & ((LayerMask)(ref fieldValue)).value) == 0)
			{
				return;
			}
			HashSet<Rigidbody> fieldValue2 = HarmonyUtil.GetFieldValue<HashSet<Rigidbody>>(__instance, "affectedRigidbodies");
			if ((fieldValue2 != null && fieldValue2.Contains(targetRigidbody)) || !((NetworkBehaviour)__instance).isServer)
			{
				return;
			}
			NetworkIdentity fieldValue3 = HarmonyUtil.GetFieldValue<NetworkIdentity>(__instance, "Caster");
			Vector3 forward = ((Component)__instance).transform.forward;
			if (TryMarkTargetDamaged(__instance, targetIdentity))
			{
				NpcBehaviour val = default(NpcBehaviour);
				if (((Component)targetIdentity).TryGetComponent<NpcBehaviour>(ref val))
				{
					val.OnHit(num, forward, false, fieldValue3);
				}
				Pawn val2 = default(Pawn);
				if (flag3 && ((Component)targetIdentity).TryGetComponent<Pawn>(ref val2) && (Object)(object)val2.Hurtbox != (Object)null)
				{
					uint num2 = (((Object)(object)fieldValue3 != (Object)null) ? fieldValue3.netId : 0u);
					val2.Hurtbox.OnHit(num, 0f, forward, (StatusSO)null, false, false, false, num2);
				}
			}
		}

		public static void ClearProjectile(ProjectilePush projectile)
		{
			if (!((Object)(object)projectile == (Object)null))
			{
				DamagedTargetsByProjectile.Remove(((Object)projectile).GetInstanceID());
			}
		}

		private static bool TryMarkTargetDamaged(ProjectilePush projectile, NetworkIdentity targetIdentity)
		{
			if ((Object)(object)projectile == (Object)null || (Object)(object)targetIdentity == (Object)null)
			{
				return false;
			}
			int instanceID = ((Object)projectile).GetInstanceID();
			uint netId = targetIdentity.netId;
			if (!DamagedTargetsByProjectile.TryGetValue(instanceID, out var value))
			{
				value = new HashSet<uint>();
				DamagedTargetsByProjectile[instanceID] = value;
			}
			if (value.Contains(netId))
			{
				return false;
			}
			value.Add(netId);
			return true;
		}

		private static bool IsAeroProjectile(ProjectilePush projectile)
		{
			Spell fieldValue = HarmonyUtil.GetFieldValue<Spell>(projectile, "OwnerSpell");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return false;
			}
			return ((object)fieldValue).GetType() == typeof(PushSpell);
		}

		private static bool IsLevitationBlastProjectile(ProjectilePush projectile)
		{
			Spell fieldValue = HarmonyUtil.GetFieldValue<Spell>(projectile, "OwnerSpell");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return false;
			}
			return ((object)fieldValue).GetType() == typeof(LevitationBlastSpell);
		}
	}
	[HarmonyPatch(typeof(ProjectilePush), "OnDestroy")]
	public class ProjectilePushDamageCleanupPatch
	{
		public static void Prefix(ProjectilePush __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				ProjectilePushDamagePatch.ClearProjectile(__instance);
			}
		}
	}
}
namespace Artisan.Features.Monsters
{
	[HarmonyPatch]
	public static class NpcHurtboxClientHitFxPatch
	{
		[HarmonyTargetMethod]
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(NpcHurtbox), "UserCode_RpcOnHit__Int32__Vector3", (Type[])null, (Type[])null);
		}

		[HarmonyPostfix]
		private static void Postfix(NpcHurtbox __instance, int damage, Vector3 forceDir)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (!ArtisanMod.EnableShowMonstersHealthBar.Value && !ArtisanMod.EnableShowMonsterDamageIndicator.Value))
			{
				return;
			}
			try
			{
				if (ArtisanMod.EnableShowMonstersHealthBar.Value)
				{
					ArtisanEnemyHealthBar artisanEnemyHealthBar = ((Component)__instance).GetComponent<ArtisanEnemyHealthBar>();
					if ((Object)(object)artisanEnemyHealthBar == (Object)null)
					{
						artisanEnemyHealthBar = ((Component)__instance).gameObject.AddComponent<ArtisanEnemyHealthBar>();
					}
					artisanEnemyHealthBar.EnsureInitialized();
					artisanEnemyHealthBar.ResetTimer();
					artisanEnemyHealthBar.UpdateHealthDisplay();
				}
				if (ArtisanMod.EnableShowMonsterDamageIndicator.Value)
				{
					ArtisanDamageTextFactory.Create(GetDamageIndicatorPosition(__instance), Mathf.Clamp(damage, 1, 9999));
				}
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[MonsterHealthBar] Failed to render hit UI: " + ex));
			}
		}

		private static Vector3 GetDamageIndicatorPosition(NpcHurtbox __instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)__instance).transform.position;
			NpcBehaviour val = default(NpcBehaviour);
			if (((Component)__instance).TryGetComponent<NpcBehaviour>(ref val))
			{
				if ((Object)(object)val.Rigidbody != (Object)null)
				{
					position = ((Component)val.Rigidbody).transform.position;
				}
				else if ((Object)(object)val.CameraTargetTransform != (Object)null)
				{
					position = val.CameraTargetTransform.position;
				}
			}
			return position + new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(1f, 1.5f), Random.Range(-0.5f, 0.5f));
		}
	}
	public class ArtisanDamageText3D : MonoBehaviour
	{
		private TextMeshPro textComponent;

		private float timer = 1.5f;

		private Vector3 baseWorldPosition;

		private float floatHeight;

		private void Awake()
		{
			textComponent = ((Component)this).GetComponent<TextMeshPro>();
		}

		private void Start()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			baseWorldPosition = ((Component)this).transform.position;
			if (!((Object)(object)Camera.main == (Object)null))
			{
				((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position);
			}
		}

		private void Update()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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)
			floatHeight += Time.deltaTime * 0.8f;
			((Component)this).transform.position = baseWorldPosition + Vector3.up * floatHeight;
			if ((Object)(object)Camera.main != (Object)null)
			{
				((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position);
			}
			timer -= Time.deltaTime;
			if (timer > 0f && timer < 0.75f)
			{
				float num = Mathf.Lerp(1f, 0.5f, (0.75f - timer) / 0.75f);
				((Component)this).transform.localScale = Vector3.one * num;
			}
			if ((Object)(object)textComponent != (Object)null)
			{
				((Graphic)textComponent).color = new Color(((Graphic)textComponent).color.r, ((Graphic)textComponent).color.g, ((Graphic)textComponent).color.b, Mathf.Clamp01(timer * 2f));
			}
			if (timer <= 0f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		public void Setup(float time)
		{
			timer = time;
		}
	}
	public static class ArtisanDamageTextFactory
	{
		public static void Create(Vector3 position, int damage)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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)
			GameObject val = new GameObject("DamageText", new Type[2]
			{
				typeof(TextMeshPro),
				typeof(ArtisanDamageText3D)
			});
			TextMeshPro component = val.GetComponent<TextMeshPro>();
			ArtisanDamageText3D component2 = val.GetComponent<ArtisanDamageText3D>();
			((TMP_Text)component).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component).text = $"-{damage}";
			Color color = default(Color);
			float fontSize;
			float time;
			if (damage >= 50)
			{
				color = Color.red;
				fontSize = 6f;
				time = 3f;
			}
			else if (damage >= 25)
			{
				color = Color.yellow;
				fontSize = 5f;
				time = 2f;
			}
			else
			{
				((Color)(ref color))..ctor(1f, 0.5f, 0f);
				fontSize = 4f;
				time = 1.5f;
			}
			((Graphic)component).color = color;
			((TMP_Text)component).fontSize = fontSize;
			val.transform.position = position;
			component2.Setup(time);
		}
	}
	public sealed class ArtisanEnemyHealthBar : MonoBehaviour
	{
		private sealed class Billboard : MonoBehaviour
		{
			private Camera mainCamera;

			private void LateUpdate()
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)mainCamera == (Object)null)
				{
					mainCamera = Camera.main;
				}
				if (!((Object)(object)mainCamera == (Object)null))
				{
					((Component)this).transform.rotation = Quaternion.Euler(((Component)mainCamera).transform.eulerAngles.x, ((Component)mainCamera).transform.eulerAngles.y, 0f);
				}
			}
		}

		private static Sprite sharedWhiteSprite;

		private readonly Vector2 size = new Vector2(20f, 2.5f);

		private readonly Color backgroundColor = new Color(0.3f, 0.3f, 0.3f, 0.9f);

		private readonly Color healthColor = Color.red;

		private float lastDamageTime;

		private bool isActive = true;

		private bool initialized;

		private Vector3 worldOffset = new Vector3(0f, 1.25f, 0f);

		private Canvas canvas;

		private Image foreground;

		private Image background;

		private TextMeshProUGUI healthText;

		private NpcHurtbox npcHurtbox;

		private NpcBehaviour npcBehaviour;

		private Transform followTransform;

		private Camera mainCamera;

		private float targetFillAmount = 1f;

		private int lastHealthCurrent = int.MinValue;

		private int lastHealthMax = int.MinValue;

		private float nextVisibilityUpdateTime;

		private float nextFollowResolveTime;

		private float nextOffsetResolveTime;

		public void EnsureInitialized()
		{
			if (!initialized)
			{
				npcHurtbox = ((Component)this).GetComponent<NpcHurtbox>();
				if (!((Object)(object)npcHurtbox == (Object)null))
				{
					npcBehaviour = ((Component)this).GetComponent<NpcBehaviour>();
					followTransform = ResolveFollowTransform();
					mainCamera = Camera.main;
					InitializeCanvas();
					UpdateWorldOffsetFromBounds(force: true);
					UpdateCanvasWorldPosition();
					UpdateHealthDisplay();
					ResetTimer();
					initialized = true;
				}
			}
		}

		public void ResetTimer()
		{
			lastDamageTime = Time.time;
			if (!isActive && (Object)(object)canvas != (Object)null)
			{
				ReactivateHealthBar();
			}
		}

		public void UpdateHealthDisplay()
		{
			if (!((Object)(object)npcHurtbox == (Object)null))
			{
				int num = Mathf.Max(0, npcHurtbox.MaxHealth);
				int num2 = Mathf.Clamp(npcHurtbox.Health, 0, num);
				if (num > 0)
				{
					targetFillAmount = Mathf.Clamp01((float)num2 / (float)num);
				}
				else
				{
					targetFillAmount = 0f;
				}
				UpdateHealthText();
			}
		}

		private void InitializeCanvas()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			GameObject val = new GameObject("ArtisanEnemyHealthCanvas");
			canvas = val.AddComponent<Canvas>();
			canvas.renderMode = (RenderMode)2;
			((Component)canvas).transform.SetParent(((Object)(object)followTransform != (Object)null) ? followTransform : ((Component)this).transform, false);
			((Component)canvas).transform.localPosition = worldOffset;
			RectTransform component = ((Component)canvas).GetComponent<RectTransform>();
			component.sizeDelta = size;
			((Transform)component).localScale = new Vector3(0.03f, 0.03f, 0.03f);
			background = CreateBarElement(((Component)canvas).transform, backgroundColor, "Background");
			foreground = CreateBarElement(((Component)canvas).transform, healthColor, "Foreground");
			foreground.type = (Type)3;
			foreground.fillMethod = (FillMethod)0;
			foreground.fillOrigin = 0;
			foreground.fillAmount = targetFillAmount;
			val.AddComponent<Billboard>();
			CreateHealthText(((Component)canvas).transform);
		}

		private Transform ResolveFollowTransform()
		{
			if ((Object)(object)npcBehaviour != (Object)null)
			{
				if ((Object)(object)npcBehaviour.Rigidbody != (Object)null)
				{
					return ((Component)npcBehaviour.Rigidbody).transform;
				}
				if ((Object)(object)npcBehaviour.CameraTargetTransform != (Object)null)
				{
					return npcBehaviour.CameraTargetTransform;
				}
			}
			return ((Component)this).transform;
		}

		private Transform ResolveBoundsRoot()
		{
			if (!((Object)(object)npcBehaviour != (Object)null))
			{
				return ((Component)this).transform;
			}
			return ((Component)npcBehaviour).transform;
		}

		private void Update()
		{
			EnsureInitialized();
			if (!initialized || !isActive)
			{
				return;
			}
			if (Time.time - lastDamageTime > 10f)
			{
				HideHealthBar();
			}
			else if (!((Object)(object)npcHurtbox == (Object)null) && !((Object)(object)foreground == (Object)null) && !((Object)(object)background == (Object)null))
			{
				RefreshFollowTransform();
				UpdateWorldOffsetFromBounds(force: false);
				UpdateCanvasWorldPosition();
				UpdateHealthValues();
				UpdateForegroundAnimation();
				if (Time.time >= nextVisibilityUpdateTime)
				{
					UpdateCanvasVisibility();
					nextVisibilityUpdateTime = Time.time + 0.1f;
				}
			}
		}

		private void RefreshFollowTransform()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextFollowResolveTime)
			{
				return;
			}
			Transform val = ResolveFollowTransform();
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)followTransform)
			{
				followTransform = val;
				if ((Object)(object)canvas != (Object)null)
				{
					((Component)canvas).transform.SetParent(followTransform, false);
					((Component)canvas).transform.localPosition = worldOffset;
				}
				UpdateWorldOffsetFromBounds(force: true);
			}
			nextFollowResolveTime = Time.time + 0.5f;
		}

		private void UpdateHealthValues()
		{
			int health = npcHurtbox.Health;
			int maxHealth = npcHurtbox.MaxHealth;
			if (maxHealth > 0 && (health != lastHealthCurrent || maxHealth != lastHealthMax))
			{
				lastHealthCurrent = health;
				lastHealthMax = maxHealth;
				targetFillAmount = Mathf.Clamp01((float)health / (float)maxHealth);
				UpdateHealthText();
			}
		}

		private void UpdateForegroundAnimation()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			foreground.fillAmount = Mathf.Lerp(foreground.fillAmount, targetFillAmount, Time.deltaTime * 10f);
			Color color = ((Graphic)foreground).color;
			if (targetFillAmount < 0.3f)
			{
				float num = Mathf.PingPong(Time.time * 2f, 1f);
				((Graphic)foreground).color = new Color(1f, num, num, color.a);
			}
			else
			{
				((Graphic)foreground).color = new Color(healthColor.r, healthColor.g, healthColor.b, color.a);
			}
		}

		private void UpdateWorldOffsetFromBounds(bool force)
		{
			//IL_0051: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (!force && Time.time < nextOffsetResolveTime)
			{
				return;
			}
			nextOffsetResolveTime = Time.time + 1f;
			Transform val = ResolveBoundsRoot();
			if (!((Object)(object)val == (Object)null) && !((Object)(object)followTransform == (Object)null) && TryGetWorldBounds(val, out var bounds))
			{
				float y = followTransform.position.y;
				float num = Mathf.Clamp(((Bounds)(ref bounds)).max.y - y + 0.15f, 0.35f, 12f);
				float num2 = ((ArtisanMod.MonsterHealthBarExtraHeightOffset != null) ? ArtisanMod.MonsterHealthBarExtraHeightOffset.Value : 0.55f);
				float num3 = Mathf.Clamp(num + num2, 0.35f, 20f);
				if (!(Mathf.Abs(worldOffset.y - num3) <= 0.01f))
				{
					worldOffset = new Vector3(worldOffset.x, num3, worldOffset.z);
					UpdateCanvasWorldPosition();
				}
			}
		}

		private void UpdateCanvasWorldPosition()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)canvas == (Object)null) && !((Object)(object)followTransform == (Object)null))
			{
				((Component)canvas).transform.position = followTransform.position + new Vector3(worldOffset.x, 0f, worldOffset.z) + Vector3.up * worldOffset.y;
			}
		}

		private static bool TryGetWorldBounds(Transform root, out Bounds bounds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			bool flag = false;
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !val.isTrigger)
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
			if (flag)
			{
				return true;
			}
			Renderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if (!flag)
					{
						bounds = val2.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val2.bounds);
					}
				}
			}
			return flag;
		}

		private void CreateHealthText(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("HealthText");
			val.transform.SetParent(parent, false);
			healthText = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)healthText).alignment = (TextAlignmentOptions)514;
			((TMP_Text)healthText).fontSize = 10f;
			((Graphic)healthText).color = Color.white;
			((TMP_Text)healthText).margin = new Vector4(0f, 0f, 0f, 10f);
			RectTransform component = ((Component)healthText).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = new Vector2(0f, 5f);
			component.sizeDelta = new Vector2(100f, 20f);
		}

		private void UpdateHealthText()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)healthText == (Object)null) && !((Object)(object)npcHurtbox == (Object)null))
			{
				int num = Mathf.Max(0, npcHurtbox.MaxHealth);
				int num2 = Mathf.Clamp(npcHurtbox.Health, 0, num);
				((TMP_Text)healthText).text = num2 + "/" + num;
				if (num > 0 && (float)num2 / (float)num < 0.3f)
				{
					((Graphic)healthText).color = Color.yellow;
				}
				else
				{
					((Graphic)healthText).color = Color.white;
				}
			}
		}

		private Image CreateBarElement(Transform parent, Color color, string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			val2.sprite = GetSharedWhiteSprite();
			((Graphic)val2).color = color;
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			return val2;
		}

		private static Sprite GetSharedWhiteSprite()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sharedWhiteSprite != (Object)null)
			{
				return sharedWhiteSprite;
			}
			Texture2D whiteTexture = Texture2D.whiteTexture;
			sharedWhiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f));
			return sharedWhiteSprite;
		}

		private void UpdateCanvasVisibility()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_00b6: 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_00d1: 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)
			if ((Object)(object)mainCamera == (Object)null)
			{
				mainCamera = Camera.main;
			}
			if (!((Object)(object)mainCamera == (Object)null) && !((Object)(object)foreground == (Object)null) && !((Object)(object)background == (Object)null))
			{
				Vector3 val = (((Object)(object)canvas != (Object)null) ? ((Component)canvas).transform.position : ((Component)this).transform.position);
				float num = Vector3.Distance(((Component)mainCamera).transform.position, val);
				float num2 = Mathf.Clamp01(1f - num / 50f);
				((Graphic)foreground).color = new Color(((Graphic)foreground).color.r, ((Graphic)foreground).color.g, ((Graphic)foreground).color.b, num2);
				((Graphic)background).color = new Color(backgroundColor.r, backgroundColor.g, backgroundColor.b, num2 * 0.8f);
				if ((Object)(object)healthText != (Object)null)
				{
					((TMP_Text)healthText).alpha = num2;
				}
			}
		}

		private void ReactivateHealthBar()
		{
			isActive = true;
			if ((Object)(object)canvas != (Object)null)
			{
				((Component)canvas).gameObject.SetActive(true);
			}
			UpdateHealthDisplay();
			UpdateCanvasVisibility();
		}

		private void HideHealthBar()
		{
			isActive = false;
			if ((Object)(object)canvas != (Object)null)
			{
				((Component)canvas).gameObject.SetActive(false);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)canvas).gameObject);
			}
			canvas = null;
		}
	}
}
namespace Artisan.Features.Inventory
{
	public static class ArtisanInventoryUpgradeEffects
	{
		private const string ShopkeeperPurchaseRpcName = "RpcOnPurchaseMade";

		private const string ChestName = "Artisan_InventoryUpgradeChest";

		public static void PlayPurchaseSuccess(PawnInventory inventory)
		{
			if (!((Object)(object)inventory == (Object)null))
			{
				PlayShopkeeperPurchaseReaction();
			}
		}

		public static void PlayLocalPurchaseSfx()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			EventReference val = FindShopPurchaseSfx();
			AudioManager val2 = default(AudioManager);
			if (!((EventReference)(ref val)).IsNull && Service.Get<AudioManager>(ref val2))
			{
				Vector3 val3 = FindPurchaseSfxPosition();
				val2.PlayEvent(val, val3, 1f, true, (Transform)null, true);
			}
		}

		private static void PlayShopkeeperPurchaseReaction()
		{
			ShopkeeperStateMachine val = Object.FindFirstObjectByType<ShopkeeperStateMachine>();
			if (!((Object)(object)val == (Object)null))
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(ShopkeeperStateMachine), "RpcOnPurchaseMade", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ArtisanMod.Logger.LogWarning((object)"Could not find ShopkeeperStateMachine.RpcOnPurchaseMade.");
				}
				else
				{
					methodInfo.Invoke(val, new object[1]);
				}
			}
		}

		private static EventReference FindShopPurchaseSfx()
		{
			//IL_001f: 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)
			Shop val = Object.FindFirstObjectByType<Shop>();
			if ((Object)(object)val == (Object)null)
			{
				return default(EventReference);
			}
			return HarmonyUtil.GetFieldValue<EventReference>(val, "purchaseSfx");
		}

		private static Vector3 FindPurchaseSfxPosition()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("Artisan_InventoryUpgradeChest");
			if ((Object)(object)val != (Object)null)
			{
				return val.transform.position;
			}
			Shop val2 = Object.FindFirstObjectByType<Shop>();
			if ((Object)(object)val2 != (Object)null)
			{
				return ((Component)val2).transform.position;
			}
			return Vector3.zero;
		}
	}
	public static class ArtisanInventoryUpgradeNetwork
	{
		private const string CommandSignature = "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()";

		private const string TargetRpcSignature = "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()";

		private static readonly int CommandHash = Extensions.GetStableHashCode("System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()");

		private static readonly int TargetRpcHash = Extensions.GetStableHashCode("System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()");

		private static bool registered;

		public static void Register()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (!registered)
			{
				RemoteProcedureCalls.RegisterCommand(typeof(PawnInventory), "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()", new RemoteCallDelegate(InvokeCmdPurchaseInventoryUpgrade), false);
				RemoteProcedureCalls.RegisterRpc(typeof(PawnInventory), "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()", new RemoteCallDelegate(InvokeTargetRpcInventoryUpgradePurchased));
				registered = true;
				ArtisanMod.Logger.LogInfo((object)"Registered Artisan inventory upgrade command.");
			}
		}

		public static void RequestPurchase(PawnInventory inventory)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return;
			}
			if (NetworkServer.active)
			{
				if (ArtisanInventoryUpgradeService.TryPurchaseNextUpgrade(inventory))
				{
					SendPurchaseSuccess(inventory, ((NetworkBehaviour)inventory).connectionToClient);
				}
				return;
			}
			NetworkWriterPooled val = NetworkWriterPool.Get();
			try
			{
				AccessTools.Method(typeof(NetworkBehaviour), "SendCommandInternal", (Type[])null, (Type[])null).Invoke(inventory, new object[5] { "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()", CommandHash, val, 0, true });
			}
			finally
			{
				NetworkWriterPool.Return(val);
			}
		}

		private static void InvokeCmdPurchaseInventoryUpgrade(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection)
		{
			if (NetworkServer.active)
			{
				PawnInventory val = (PawnInventory)(object)((obj is PawnInventory) ? obj : null);
				if (!((Object)(object)val == (Object)null) && ArtisanInventoryUpgradeService.TryPurchaseNextUpgrade(val))
				{
					SendPurchaseSuccess(val, senderConnection);
				}
			}
		}

		private static void SendPurchaseSuccess(PawnInventory inventory, NetworkConnectionToClient connection)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return;
			}
			ArtisanInventoryUpgradeEffects.PlayPurchaseSuccess(inventory);
			if (connection == null)
			{
				return;
			}
			NetworkWriterPooled val = NetworkWriterPool.Get();
			try
			{
				AccessTools.Method(typeof(NetworkBehaviour), "SendTargetRPCInternal", (Type[])null, (Type[])null).Invoke(inventory, new object[5] { connection, "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()", TargetRpcHash, val, 0 });
			}
			finally
			{
				NetworkWriterPool.Return(val);
			}
		}

		private static void InvokeTargetRpcInventoryUpgradePurchased(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection)
		{
			ArtisanInventoryUpgradeEffects.PlayLocalPurchaseSfx();
			ArtisanLockedSlotOverlayPatch.RefreshCurrentInventory();
		}
	}
	[HarmonyPatch]
	public static class ArtisanInventoryLockedSlotPatch
	{
		private static bool HasAvailablePickupSpace(PawnInventory inventory)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return false;
			}
			if (ArtisanInventoryUpgradeService.GetFirstUnlockedEmptySlot(inventory) >= 0)
			{
				return true;
			}
			PawnPropInteractions component = ((Component)inventory).GetComponent<PawnPropInteractions>();
			if ((Object)(object)component != (Object)null)
			{
				return (Object)(object)component.NetworkCurrentLeftHandNetworkProp == (Object)null;
			}
			return false;
		}

		[HarmonyPatch(typeof(PawnInventory), "SelectSlotWithMainHand")]
		[HarmonyPrefix]
		private static bool SelectSlotWithMainHandPrefix(PawnInventory __instance, int slotIndex)
		{
			return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex);
		}

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSelectSlotWithMainHand__Int32")]
		[HarmonyPrefix]
		private static bool CmdSelectSlotPrefix(PawnInventory __instance, int slotIndex)
		{
			return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex);
		}

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSwapSlotWithRightHand__Int32")]
		[HarmonyPrefix]
		private static bool CmdSwapSlotPrefix(PawnInventory __instance, int slotIndex)
		{
			return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex);
		}

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdMoveItemInInventory__UInt32__Int32")]
		[HarmonyPrefix]
		private static bool CmdMoveItemPrefix(PawnInventory __instance, uint sourcePropNetId, int targetSlotIndex)
		{
			return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, targetSlotIndex);
		}

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdCycleSlot__Boolean")]
		[HarmonyPrefix]
		private static bool CmdCycleSlotPrefix(PawnInventory __instance, bool cycleForward)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return true;
			}
			int unlockedSlotCount = ArtisanInventoryUpgradeService.GetUnlockedSlotCount(__instance);
			if (unlockedSlotCount <= 0)
			{
				return false;
			}
			int num = __instance.CurrentMainHandSlot;
			for (int i = 0; i < unlockedSlotCount; i++)
			{
				num = (cycleForward ? (num - 1) : (num + 1));
				if (num < 0)
				{
					num = unlockedSlotCount - 1;
				}
				else if (num >= unlockedSlotCount)
				{
					num = 0;
				}
				if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, num))
				{
					__instance.SelectSlotWithMainHand(num);
					return false;
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdAttemptPickup__NetworkPuppetProp")]
		[HarmonyPrefix]
		private static bool CmdAttemptPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return true;
			}
			int currentMainHandSlot = __instance.CurrentMainHandSlot;
			if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, currentMainHandSlot))
			{
				return true;
			}
			__instance.ServerTryPickup(prop, 0);
			return false;
		}

		[HarmonyPatch(typeof(UIInventory), "OnSlotDrop")]
		[HarmonyPrefix]
		private static bool OnSlotDropPrefix(UIInventory __instance, UIInventorySlot targetSlot)
		{
			PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory");
			UIInventorySlot fieldValue2 = HarmonyUtil.GetFieldValue<UIInventorySlot>(__instance, "_draggedSlot");
			if ((Object)(object)fieldValue == (Object)null || (Object)(object)targetSlot == (Object)null)
			{
				return true;
			}
			if (IsLockedInventorySlot(fieldValue, targetSlot) || IsLockedInventorySlot(fieldValue, fieldValue2))
			{
				__instance.StopDrag();
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(PawnInventory), "ServerTryPickup")]
		[HarmonyPrefix]
		private static bool ServerTryPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop, int preferredSlotIndex, ref bool __result)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return true;
			}
			if ((Object)(object)prop == (Object)null || !prop.CanPickedUpBy(((NetworkBehaviour)__instance).netIdentity))
			{
				__result = false;
				return false;
			}
			if (preferredSlotIndex == -1)
			{
				preferredSlotIndex = __instance.CurrentMainHandSlot;
			}
			if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, preferredSlotIndex) && __instance.ServerTryPickupInventorySlotOnly(prop, preferredSlotIndex))
			{
				__result = true;
				return false;
			}
			PawnPropInteractions fieldValue = HarmonyUtil.GetFieldValue<PawnPropInteractions>(__instance, "propInteractions");
			if ((Object)(object)fieldValue != (Object)null && (Object)(object)fieldValue.NetworkCurrentLeftHandNetworkProp == (Object)null)
			{
				prop.ServerHandleHeld(fieldValue, false);
				__result = true;
				return false;
			}
			int firstUnlockedEmptySlot = ArtisanInventoryUpgradeService.GetFirstUnlockedEmptySlot(__instance);
			if (firstUnlockedEmptySlot < 0)
			{
				__result = false;
				return false;
			}
			__result = __instance.ServerTryPickupInventorySlotOnly(prop, firstUnlockedEmptySlot);
			return false;
		}

		[HarmonyPatch(typeof(PawnInventory), "ServerTryPickupInventorySlotOnly")]
		[HarmonyPrefix]
		private static bool ServerTryPickupInventorySlotOnlyPrefix(PawnInventory __instance, int slotIndex, ref bool __result)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return true;
			}
			if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex))
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(NetworkPuppetProp), "CanInteract")]
		[HarmonyPostfix]
		private static void NetworkPuppetPropCanInteractPostfix(NetworkPuppetProp __instance, NetworkIdentity identity, ref bool __result)
		{
			if (__result && ArtisanInventoryUpgradeService.IsEnabled())
			{
				PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>());
				if (!((Object)(object)val == (Object)null) && !HasAvailablePickupSpace(val))
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(NetworkPuppetProp), "ShowTooltip")]
		[HarmonyPrefix]
		private static bool NetworkPuppetPropShowTooltipPrefix(NetworkPuppetProp __instance, NetworkIdentity identity)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return true;
			}
			PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>());
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (HasAvailablePickupSpace(val))
			{
				return true;
			}
			UIManager instance = UIManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.uiTooltip == (Object)null)
			{
				return false;
			}
			string text = __instance.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")";
			instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, __instance.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, __instance.IsGrabable, false, (string)null, (InputTarget)9, true, false);
			return false;
		}

		[HarmonyPatch(typeof(PropIngredient), "CustomTooltipAction")]
		[HarmonyPostfix]
		private static void PropIngredientCustomTooltipActionPostfix(PropIngredient __instance, Interactable interactable, NetworkIdentity identity)
		{
			if (!ArtisanInventoryUpgradeService.IsEnabled())
			{
				return;
			}
			PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>());
			if ((Object)(object)val == (Object)null || HasAvailablePickupSpace(val))
			{
				return;
			}
			NetworkPuppetProp val2 = (NetworkPuppetProp)(object)((interactable is NetworkPuppetProp) ? interactable : null);
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = ((Component)__instance).GetComponent<NetworkPuppetProp>();
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				UIManager instance = UIManager.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.uiTooltip == (Object)null))
				{
					string text = val2.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")";
					instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, (string)null, (InputTarget)8, val2.IsGrabable, false, val2.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, val2.IsGrabable, false);
				}
			}
		}

		[HarmonyPatch(typeof(UIInventory), "OnDragHoverEnter")]
		[HarmonyPrefix]
		private static bool OnDragHoverEnterPrefix(UIInventory __instance, UIInventorySlot slot)
		{
			return !IsLockedInventorySlot(HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory"), slot);
		}

		[HarmonyPatch(typeof(UIInventorySlot), "OnBeginDrag")]
		[HarmonyPrefix]
		private static bool OnBeginDragPrefix(UIInventorySlot __instance)
		{
			return !IsLockedInventorySlot(HarmonyUtil.GetFieldValue<PawnInventory>(HarmonyUtil.GetFieldValue<UIInventory>(__instance, "_inventory"), "_playerInventory"), __instance);
		}

		private static bool IsLockedInventorySlot(PawnInventory inventory, UIInventorySlot slot)
		{
			if ((Object)(object)inventory == (Object)null || (Object)(object)slot == (Object)null || slot.IsHandSlot)
			{
				return false;
			}
			return !ArtisanInventoryUpgradeService.IsSlotUnlocked(inventory, slot.SlotIndex);
		}
	}
	[HarmonyPatch(typeof(Interactable), "Interact")]
	public static class ArtisanInventoryUpgradeStationInteractPatch
	{
		private static bool Prefix(Interactable __instance)
		{
			return !(__instance is ArtisanInventoryUpgradeStationInteractable);
		}
	}
	[HarmonyPatch(typeof(Shop), "OnStartClient")]
	public static class ArtisanInventoryUpgradeStationPatch
	{
		private const string PrefabName = "Chest_Small_interactive";

		private const string ObjectName = "Artisan_InventoryUpgradeChest";

		private static void Postfix(Shop __instance)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameObject.Find("Artisan_InventoryUpgradeChest") != (Object)null) && ArtisanInventoryUpgradeService.IsEnabled())
			{
				GameObject val = FindPrefab("Chest_Small_interactive");
				if ((Object)(object)val == (Object)null)
				{
					ArtisanMod.Logger.LogWarning((object)"Could not find prefab: Chest_Small_interactive");
					return;
				}
				Vector3 val2 = ((Component)__instance).transform.position + ((Component)__instance).transform.right * -2f;
				val2.y += 0.25f;
				GameObject obj = Object.Instantiate<GameObject>(val, val2, Quaternion.Euler(0f, ((Component)__instance).transform.eulerAngles.y, 0f));
				((Object)obj).name = "Artisan_InventoryUpgradeChest";
				obj.SetActive(true);
				StripGameplayComponents(obj);
				EnsureCollider(obj);
				ArtisanInventoryUpgradeStationInteractable artisanInventoryUpgradeStationInteractable = obj.AddComponent<ArtisanInventoryUpgradeStationInteractable>();
				((Interactable)artisanInventoryUpgradeStationInteractable).HoldInteractDuration = 1.25f;
				((Interactable)artisanInventoryUpgradeStationInteractable).RefreshLocalInteractable();
				ArtisanMod.Logger.LogInfo((object)"Spawned inventory upgrade chest in lobby.");
			}
		}

		private static GameObject FindPrefab(string prefabName)
		{
			GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
			foreach (GameObject val in array)
			{
				if (!((Object)(object)val == (Object)null) && (((Object)val).name == prefabName || ((Object)val).name == prefabName + ".prefab"))
				{
					return val;
				}
			}
			return null;
		}

		private static void StripGameplayComponents(GameObject root)
		{
			Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
			for (int num = componentsInChildren.Length - 1; num >= 0; num--)
			{
				Component val = componentsInChildren[num];
				if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is MeshRenderer) && !(val is SkinnedMeshRenderer) && !(val is MeshFilter) && !(val is Animator) && !(val is Collider))
				{
					Object.Destroy((Object)(object)val);
				}
			}
			SetActiveRecursively(root.transform);
		}

		private static void SetActiveRecursively(Transform transform)
		{
			((Component)transform).gameObject.SetActive(true);
			for (int i = 0; i < transform.childCount; i++)
			{
				SetActiveRecursively(transform.GetChild(i));
			}
		}

		private static void EnsureCollider(GameObject root)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)root.GetComponentInChildren<Collider>() != (Object)null))
			{
				BoxCollider obj = root.AddComponent<BoxCollider>();
				obj.size = new Vector3(1.2f, 0.8f, 0.8f);
				obj.center = new Vector3(0f, 0.4f, 0f);
			}
		}
	}
	public sealed class ArtisanInventoryUpgradeStationInteractable : Interactable
	{
		protected override void Awake()
		{
			((Interactable)this).Awake();
			((Interactable)this).CanInteractAction += CannotInteract;
			((Interactable)this).CanHoldInteractAction += CanHoldInteract;
			((Interactable)this).CustomTooltipAction += ShowTooltip;
		}

		protected override void OnDestroy()
		{
			((Interactable)this).CanInteractAction -= CannotInteract;
			((Interactable)this).CanHoldInteractAction -= CanHoldInteract;
			((Interactable)this).CustomTooltipAction -= ShowTooltip;
			((Interactable)this).OnDestroy();
		}

		public void ShowUpgradeTooltip(NetworkIdentity identity)
		{
			ShowTooltip((Interactable)(object)this, identity);
		}

		private bool CannotInteract(NetworkIdentity identity, Interactable interactable)
		{
			return false;
		}

		private bool CanHoldInteract(NetworkIdentity identity, Interactable interactable)
		{
			PawnInventory inventory = GetInventory(identity);
			if ((Object)(object)inventory != (Object)null)
			{
				return ArtisanInventoryUpgradeService.CanPurchaseNextUpgrade(inventory);
			}
			return false;
		}

		private void ShowTooltip(Interactable interactable, NetworkIdentity identity)
		{
			PawnInventory inventory = GetInventory(identity);
			if (!((Object)(object)inventory == (Object)null))
			{
				int unlockedExtraSlots = ArtisanInventoryUpgradeService.GetUnlockedExtraSlots(inventory);
				int maxExtraSlots = ArtisanInventoryUpgradeService.GetMaxExtraSlots();
				if (unlockedExtraSlots >= maxExtraSlots)
				{
					UIManager.Instance.uiTooltip.ShowTooltip(ArtisanText.Format("inventory_upgrade_full"), (InputTarget)2, false, false, (string)null, (InputTarget)8, true, false, (string)null, (InputTarget)9, true, false);
					return;
				}
				int nextUpgradePrice = ArtisanInventoryUpgradeService.GetNextUpgradePrice(inventory);
				bool flag = ArtisanInventoryUpgradeService.CanPurchaseNextUpgrade(inventory);
				UIManager.Instance.uiTooltip.ShowTooltip(ArtisanText.Format("inventory_upgrade_buy", nextUpgradePrice), (InputTarget)2, flag, true, (string)null, (InputTarget)8, true, false, (string)null, (InputTarget)9, true, false);
			}
		}

		private static PawnInventory GetInventory(NetworkIdentity identity)
		{
			if (!((Object)(object)identity == (Object)null))
			{
				return ((Component)identity).GetComponent<PawnInventory>();
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Interactable), "HoldInteract")]
	public static class ArtisanInventoryUpgradeStationHoldPatch
	{
		[CompilerGenerated]
		private sealed class <RefreshTooltipAfterPurchase>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public ArtisanInventoryUpgradeStationInteractable station;

			public NetworkIdentity identity;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RefreshTooltipAfterPurchase>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.15f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if ((Object)(object)station == (Object)null)
					{
						return false;
					}
					((Interactable)station).RefreshLocalInteractable();
					ArtisanLockedSlotOverlayPatch.RefreshCurrentInventory();
					UIManager instance = UIManager.Instance;
					if ((Object)(object)instance == (Object)null || (Object)(object)instance.uiTooltip == (Object)null)
					{
						return false;
					}
					station.ShowUpgradeTooltip(identity);
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static bool Prefix(Interactable __instance, NetworkIdentity identity)
		{
			if (!(__instance is ArtisanInventoryUpgradeStationInteractable))
			{
				return true;
			}
			PawnInventory inventory = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>());
			UIManager instance = UIManager.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.uiTooltip != (Object)null)
			{
				instance.uiTooltip.HideTooltip();
			}
			ArtisanInventoryUpgradeNetwork.RequestPurchase(inventory);
			ArtisanInventoryUpgradeStationInteractable artisanInventoryUpgradeStationInteractable = __instance as ArtisanInventoryUpgradeStationInteractable;
			if ((Object)(object)artisanInventoryUpgradeStationInteractable != (Object)null)
			{
				((MonoBehaviour)artisanInventoryUpgradeStationInteractable).StartCoroutine(RefreshTooltipAfterPurchase(artisanInventoryUpgradeStationInteractable, identity));
			}
			return false;
		}

		[IteratorStateMachine(typeof(<RefreshTooltipAfterPurchase>d__1))]
		private static IEnumerator RefreshTooltipAfterPurchase(ArtisanInventoryUpgradeStationInteractable station, NetworkIdentity identity)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RefreshTooltipAfterPurchase>d__1(0)
			{
				station = station,
				identity = identity
			};
		}
	}
	[HarmonyPatch]
	public static class InventoryPersistencePatch
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

			MethodBase IEnumerator<MethodBase>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TargetMethods>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(PawnInventory), "ServerSerializeToKvp", (Type[])null, (Type[])null);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(PawnInventory), "ServerTryRestoreFromKvp", (Type[])null, (Type[])null);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__0(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<MethodBase>)this).GetEnumerator();
			}
		}

		[IteratorStateMachine(typeof(<TargetMethods>d__0))]
		[HarmonyTargetMethods]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__0(-2);
		}

		private static void Postfix(PawnInventory __instance, SaveManager save, string playerId, MethodBase __originalMethod)
		{
			if (!IsEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)save == (Object)null || string.IsNullOrEmpty(playerId))
			{
				return;
			}
			try
			{
				if (__originalMethod.Name == "ServerSerializeToKvp")
				{
					SerializeExtendedSlots(__instance, save, playerId);
				}
				else if (__originalMethod.Name == "ServerTryRestoreFromKvp")
				{
					RestoreExtendedSlots(__instance, save, playerId);
				}
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed: " + ex.Message));
			}
		}

		private static void SerializeExtendedSlots(PawnInventory inventory, SaveManager save, string playerId)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			string keyPrefix = GetKeyPrefix(playerId);
			int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots();
			save.SetInt(keyPrefix + ".SLOT_COUNT", maxInventorySlots);
			save.SetInt(keyPrefix + ".MAIN", Mathf.Clamp(inventory.CurrentMainHandSlot, 0, maxInventorySlots - 1));
			MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "SerializeProp", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return;
			}
			for (int i = 0; i < maxInventorySlots; i++)
			{
				NetworkPuppetProp val = null;
				if (i < inventory.Items.Count)
				{
					InventoryItem val2 = inventory.Items[i];
					if (!((InventoryItem)(ref val2)).IsEmpty)
					{
						val2 = inventory.Items[i];
						val = ((InventoryItem)(ref val2)).PropInstance;
					}
				}
				methodInfo.Invoke(inventory, new object[3]
				{
					save,
					keyPrefix + ".S" + i,
					val
				});
			}
		}

		private static void RestoreExtendedSlots(PawnInventory inventory, SaveManager save, string playerId)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			string keyPrefix = GetKeyPrefix(playerId);
			int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots();
			MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "TryRestoreProp", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(PawnInventory), "ServerAddItemToSlot", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				return;
			}
			InventoryItem val3 = default(InventoryItem);
			for (int i = 3; i < maxInventorySlots; i++)
			{
				if (i < inventory.Items.Count)
				{
					InventoryItem val = inventory.Items[i];
					if (!((InventoryItem)(ref val)).IsEmpty)
					{
						continue;
					}
				}
				object[] array = new object[4]
				{
					save,
					keyPrefix + ".S" + i,
					playerId,
					null
				};
				if (!(bool)methodInfo.Invoke(inventory, array) || array[3] == null)
				{
					continue;
				}
				object obj = array[3];
				NetworkPuppetProp val2 = (NetworkPuppetProp)((obj is NetworkPuppetProp) ? obj : null);
				if (!((Object)(object)val2 == (Object)null))
				{
					((InventoryItem)(ref val3))..ctor(val2);
					if ((bool)methodInfo2.Invoke(inventory, new object[2] { i, val3 }))
					{
						AccessTools.Field(typeof(PawnInventory), "propInteractions")?.GetValue(inventory);
						SetPropInInventory(val2, inventory);
					}
				}
			}
			RestoreSelectedMainSlot(inventory, save, keyPrefix, maxInventorySlots);
			NormalizeRestoredInventoryProps(inventory);
		}

		private static void SetPropInInventory(NetworkPuppetProp prop, PawnInventory inventory)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)prop == (Object)null) && !((Object)(object)inventory == (Object)null))
			{
				object? obj = AccessTools.Field(typeof(PawnInventory), "propInteractions")?.GetValue(inventory);
				PawnPropInteractions val = (PawnPropInteractions)((obj is PawnPropInteractions) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					prop.ServerSetInInventory(val);
				}
				else
				{
					prop.CurrentState = new PropStateData((PropState)2, (PawnPropInteractions)null, true);
				}
			}
		}

		private static void NormalizeRestoredInventoryProps(PawnInventory inventory)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)inventory == (Object)null)
			{
				return;
			}
			int currentMainHandSlot = inventory.CurrentMainHandSlot;
			for (int i = 0; i < inventory.Items.Count; i++)
			{
				if (i != currentMainHandSlot)
				{
					InventoryItem val = inventory.Items[i];
					if (!((InventoryItem)(ref val)).IsEmpty && !((Object)(object)((InventoryItem)(ref val)).PropInstance == (Object)null))
					{
						SetPropInInventory(((InventoryItem)(ref val)).PropInstance, inventory);
					}
				}
			}
			if (currentMainHandSlot >= 0 && currentMainHandSlot < inventory.Items.Count)
			{
				InventoryItem val2 = inventory.Items[currentMainHandSlot];
				if (!((InventoryItem)(ref val2)).IsEmpty)
				{
					inventory.SelectSlotWithMainHand(currentMainHandSlot);
				}
			}
		}

		private static void RestoreSelectedMainSlot(PawnInventory inventory, SaveManager save, string keyPrefix, int maxSlots)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			int num = default(int);
			if (!save.TryGetInt(keyPrefix + ".MAIN", ref num))
			{
				return;
			}
			num = Mathf.Clamp(num, 0, maxSlots - 1);
			if (num < inventory.Items.Count)
			{
				InventoryItem val = inventory.Items[num];
				if (!((InventoryItem)(ref val)).IsEmpty)
				{
					inventory.SelectSlotWithMainHand(num);
				}
			}
		}

		private static string GetKeyPrefix(string playerId)
		{
			return "PLAYER." + playerId + ".INV";
		}

		private static bool IsEnabled()
		{
			if (ArtisanMod.EnableExtendedInventorySlots != null)
			{
				return ArtisanMod.EnableExtendedInventorySlots.Value;
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class InventorySlotLimitPatch
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__1 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

			private Type <type>5__2;

			private string[] <>7__wrap2;

			private int <>7__wrap3;

			MethodBase IEnumerator<MethodBase>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TargetMethods>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<type>5__2 = null;
				<>7__wrap2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_0078;
				}
				<>1__state = -1;
				<type>5__2 = typeof(PawnInventory);
				<>7__wrap2 = TargetMethodNames;
				<>7__wrap3 = 0;
				goto IL_0086;
				IL_0078:
				<>7__wrap3++;
				goto IL_0086;
				IL_0086:
				if (<>7__wrap3 < <>7__wrap2.Length)
				{
					string text = <>7__wrap2[<>7__wrap3];
					MethodInfo methodInfo = AccessTools.Method(<type>5__2, text, (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						<>2__current = methodInfo;
						<>1__state = 1;
						return true;
					}
					goto IL_0078;
				}
				<>7__wrap2 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__1(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<MethodBase>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <Transpiler>d__2 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private CodeInstruction <>2__current;

			private int <>l__initialThreadId;

			private IEnumerable<CodeInstruction> instructions;

			public IEnumerable<CodeInstruction> <>3__instructions;

			private IEnumerator<CodeInstruction> <>7__wrap1;

			CodeInstruction IEnumerator<CodeInstruction>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Transpiler>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = instructions.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					case 2:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						CodeInstruction current = <>7__wrap1.Current;
						if (!IsEnabled())
						{
							<>2__current = current;
							<>1__state = 1;
							return true;
						}
						if (IsLdcI4(current, 3))
						{
							current.opcode = OpCodes.Call;
							current.operand = AccessTools.Method(typeof(InventorySlotLimitPatch), "GetMaxInventorySlots", (Type[])null, (Type[])null);
						}
						else if (IsLdcI4(current, 2))
						{
							current.opcode = OpCodes.Call;
							current.operand = AccessTools.Method(typeof(InventorySlotLimitPatch), "GetMaxInventorySlotIndex", (Type[])null, (Type[])null);
						}
						<>2__current = current;
						<>1__state = 2;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap1 != null)
				{
					<>7__wrap1.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
			{
				<Transpiler>d__2 <Transpiler>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<Transpiler>d__ = this;
				}
				else
				{
					<Transpiler>d__ = new <Transpiler>d__2(0);
				}
				<Transpiler>d__.instructions = <>3__instructions;
				return <Transpiler>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<CodeInstruction>)this).GetEnumerator();
			}
		}

		private static readonly string[] TargetMethodNames = new string[12]
		{
			"OnStartServer", "OnStartClient", "IsFull", "ServerTryAddItem", "ServerAddItemToSlot", "ServerRemoveFromSlot", "SelectSlotWithMainHand", "ServerSerializeToKvp", "ServerTryRestoreFromKvp", "UserCode_CmdCycleSlot__Boolean",
			"UserCode_CmdMoveItemInInventory__UInt32__Int32", "UserCode_CmdSwapSlotWithRightHand__Int32"
		};

		[IteratorStateMachine(typeof(<TargetMethods>d__1))]
		[HarmonyTargetMethods]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__1(-2);
		}

		[IteratorStateMachine(typeof(<Transpiler>d__2))]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Transpiler>d__2(-2)
			{
				<>3__instructions = instructions
			};
		}

		public static int GetMaxInventorySlots()
		{
			if (!IsEnabled())
			{
				return 3;
			}
			return Mathf.Clamp(ArtisanMod.MaxInventorySlots.Value, 3, 8);
		}

		public static int GetMaxInventorySlotIndex()
		{
			return GetMaxInventorySlots() - 1;
		}

		private static bool IsEnabled()
		{
			if (ArtisanMod.EnableExtendedInventorySlots != null)
			{
				return ArtisanMod.EnableExtendedInventorySlots.Value;
			}
			return false;
		}

		private static bool IsLdcI4(CodeInstruction instruction, int value)
		{
			if (value == 2 && instruction.opcode == OpCodes.Ldc_I4_2)
			{
				return true;
			}
			if (value == 3 && instruction.opcode == OpCodes.Ldc_I4_3)
			{
				return true;
			}
			if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num)
			{
				return num == value;
			}
			if (instruction.opcode == OpCodes.Ldc_I4_S && instruction.operand is sbyte b)
			{
				return b == value;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(UIInventory), "OnStartPawnAuthorityChanged")]
	public static class UIInventorySlotExpansionPatch
	{
		private static void Prefix(UIInventory __instance)
		{
			if ((Object)(object)__instance == (Object)null || ArtisanMod.EnableExtendedInventorySlots == null || !ArtisanMod.EnableExtendedInventorySlots.Value)
			{
				return;
			}
			UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(__instance, "inventorySlots");
			int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots();
			if (fieldValue == null || fieldValue.Length == 0 || fieldValue.Length >= maxInventorySlots)
			{
				return;
			}
			UIInventorySlot val = fieldValue[0];
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform parent = ((Component)val).transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			UIInventorySlot[] array = (UIInventorySlot[])(object)new UIInventorySlot[maxInventorySlots];
			for (int i = 0; i < fieldValue.Length; i++)
			{
				array[i] = fieldValue[i];
			}
			for (int j = fieldValue.Length; j < maxInventorySlots; j++)
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent);
				((Object)val2).name = "ArtisanInventorySlot_" + j;
				val2.SetActive(true);
				UIInventorySlot component = val2.GetComponent<UIInventorySlot>();
				if ((Object)(object)component == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					continue;
				}
				LayoutElement component2 = val2.GetComponent<LayoutElement>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.ignoreLayout = true;
				}
				array[j] = component;
			}
			HarmonyUtil.SetFieldValue(__instance, "inventorySlots", array);
		}
	}
	[HarmonyPatch(typeof(UIInventory), "Update")]
	public static class UIInventoryExtendedHotkeysPatch
	{
		private static readonly KeyCode[] SlotKeys;

		private static void Postfix(UIInventory __instance)
		{
			if (ArtisanMod.EnableExtendedInventorySlots == null || !ArtisanMod.EnableExtendedInventorySlots.Value)
			{
				return;
			}
			PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return;
			}
			int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots();
			for (int i = 3; i < maxInventorySlots && i < 8; i++)
			{
				if (ArtisanInventoryUpgradeService.IsSlotUnlocked(fieldValue, i) && Input.GetKeyDown(SlotKeys[i - 3]))
				{
					fieldValue.CmdSelectSlotWithMainHand(i);
					break;
				}
			}
		}

		static UIInventoryExtendedHotkeysPatch()
		{
			KeyCode[] array = new KeyCode[5];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			SlotKeys = (KeyCode[])(object)array;
		}
	}
	public static class ArtisanInventoryUpgradeService
	{
		private const int VanillaSlotCount = 3;

		private const string UnlockedExtraSlotsKey = ".UNLOCKED_EXTRA_SLOTS";

		public static bool IsEnabled()
		{
			if (ArtisanMod.EnableExtendedInventorySlots != null && ArtisanMod.EnableExtendedInventorySlots.Value && ArtisanMod.EnableInventorySlotUpgrades != null)
			{
				return ArtisanMod.EnableInventorySlotUpgrades.Value;
			}
			return false;
		}

		public static int GetMaxExtraSlots()
		{
			return Mathf.Max(0, InventorySlotLimitPatch.GetMaxInventorySlots() - 3);
		}

		public static int GetUnlockedExtraSlots(PawnInventory inventory)
		{
			if (!IsEnabled())
			{
				return GetMaxExtraSlots();
			}
			Pawn pawn = GetPawn(inventory);
			if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId))
			{
				return 0;
			}
			SaveManager val = default(SaveManager);
			if (!Service.Get<SaveManager>(ref val))
			{
				return 0;
			}
			int num = default(int);
			if (!val.TryGetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), ref num))
			{
				return 0;
			}
			return Mathf.Clamp(num, 0, GetMaxExtraSlots());
		}

		public static int GetUnlockedSlotCount(PawnInventory inventory)
		{
			return 3 + GetUnlockedExtraSlots(inventory);
		}

		public static bool IsSlotUnlocked(PawnInventory inventory, int slotIndex)
		{
			if (slotIndex < 3)
			{
				return true;
			}
			if (slotIndex >= 0)
			{
				return slotIndex < GetUnlockedSlotCount(inventory);
			}
			return false;
		}

		public static int GetNextUpgradePrice(PawnInventory inventory)
		{
			int unlockedExtraSlots = GetUnlockedExtraSlots(inventory);
			int num = Mathf.Max(0, ArtisanMod.ExtraSlotBasePrice.Value);
			float num2 = Mathf.Max(1f, ArtisanMod.ExtraSlotPriceMultiplier.Value);
			return Mathf.CeilToInt((float)num * Mathf.Pow(num2, (float)unlockedExtraSlots));
		}

		public static bool CanPurchaseNextUpgrade(PawnInventory inventory)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEnabled())
			{
				return false;
			}
			if (!NetworkServer.active)
			{
				return false;
			}
			if ((Object)(object)GameManager.Instance == (Object)null || (int)GameManager.Instance.CurrentGameState != 0)
			{
				return false;
			}
			Pawn pawn = GetPawn(inventory);
			if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId))
			{
				return false;
			}
			if (GetUnlockedExtraSlots(inventory) >= GetMaxExtraSlots())
			{
				return false;
			}
			return GameManager.Instance.Gold >= GetNextUpgradePrice(inventory);
		}

		public static bool TryPurchaseNextUpgrade(PawnInventory inventory)
		{
			if (!CanPurchaseNextUpgrade(inventory))
			{
				return false;
			}
			Pawn pawn = GetPawn(inventory);
			SaveManager val = default(SaveManager);
			if ((Object)(object)pawn == (Object)null || !Service.Get<SaveManager>(ref val))
			{
				return false;
			}
			int nextUpgradePrice = GetNextUpgradePrice(inventory);
			int num = GetUnlockedExtraSlots(inventory) + 1;
			GameManager.Instance.ModifyGold(-nextUpgradePrice);
			val.SetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), num);
			inventory.ServerPersistInventory();
			return true;
		}

		public static int GetFirstUnlockedEmptySlot(PawnInventory inventory)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)inventory == (Object)null)
			{
				return -1;
			}
			int unlockedSlotCount = GetUnlockedSlotCount(inventory);
			for (int i = 0; i < unlockedSlotCount; i++)
			{
				if (!IsSlotUnlocked(inventory, i))
				{
					continue;
				}
				if (i < inventory.Items.Count)
				{
					InventoryItem val = inventory.Items[i];
					if (!((InventoryItem)(ref val)).IsEmpty)
					{
						continue;
					}
				}
				return i;
			}
			return -1;
		}

		private static Pawn GetPawn(PawnInventory inventory)
		{
			if (!((Object)(object)inventory == (Object)null))
			{
				return ((Component)inventory).GetComponent<Pawn>();
			}
			return null;
		}

		private static string GetUnlockedExtraSlotsKey(string playerId)
		{
			return "PLAYER." + playerId + ".INV.UNLOCKED_EXTRA_SLOTS";
		}
	}
	[HarmonyPatch]
	public static class ArtisanLockedSlotOverlayPatch
	{
		[HarmonyPatch(typeof(UIInventory), "RefreshInventoryDisplay")]
		[HarmonyPostfix]
		private static void RefreshInventoryDisplayPostfix(UIInventory __instance)
		{
			Refresh(__instance);
		}

		public static void RefreshCurrentInventory()
		{
			if (!((Object)(object)UIManager.Instance == (Object)null) && !((Object)(object)UIManager.Instance.uiGame == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer.uiInventory == (Object)null))
			{
				Refresh(UIManager.Instance.uiGame.uiPlayer.uiInventory);
			}
		}

		private static void Refresh(UIInventory inventoryUi)
		{
			if ((Object)(object)inventoryUi == (Object)null)
			{
				return;
			}
			PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(inventoryUi, "_playerInventory");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return;
			}
			UIInventorySlot[] fieldValue2 = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(inventory