Decompiled source of Artisan v1.1.0

Artisan.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Artisan.Configuration;
using Artisan.Features.Inventory.Effects;
using Artisan.Features.Inventory.Interactables;
using Artisan.Features.Inventory.Network;
using Artisan.Features.Inventory.Patches;
using Artisan.Features.Inventory.Services;
using Artisan.Features.Inventory.UI;
using Artisan.Features.Monsters.UI;
using Artisan.Features.Spells.Patches;
using Artisan.Localization;
using Artisan.Shared.Reflection;
using Artisan.Source.Features.Spells.Context;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FMODUnity;
using HarmonyLib;
using Mirror;
using Mirror.RemoteCalls;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
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("A general-purpose quality-of-life mod for YAPYAP with inventory extension support, multiplayer monster health bars, damage indicators, and spell balance improvements.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Hadaward")]
[assembly: AssemblyProduct("Artisan")]
[assembly: AssemblyCopyright("Copyright © Hadaward 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2295655e-9260-4eae-a7c1-b44cabf62fea")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace Artisan
{
	[BepInPlugin("gamedroit.artisan", "Artisan", "1.1.0")]
	public sealed class ArtisanMod : BaseUnityPlugin
	{
		public const string PluginGuid = "gamedroit.artisan";

		public const string PluginName = "Artisan";

		public const string PluginVersion = "1.1.0";

		private Harmony _harmony;

		internal static ManualLogSource Logger { get; private set; }

		internal static ArtisanConfig Settings { get; private set; }

		public void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Settings = new ArtisanConfig(((BaseUnityPlugin)this).Config);
			InventorySlotUpgradeNetwork.Register();
			InventoryUpgradeStationInteractable.RegisterTranslations();
			_harmony = new Harmony("gamedroit.artisan");
			try
			{
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
				{
					Logger.LogDebug((object)("Patched: " + patchedMethod.DeclaringType?.FullName + "." + patchedMethod.Name));
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Harmony patch failed: {arg}");
			}
			Logger.LogInfo((object)"Artisan 1.1.0 loaded.");
		}

		public void OnDestroy()
		{
			Logger.LogInfo((object)"Artisan is being unloaded.");
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace Artisan.Shared.Reflection
{
	public static class HarmonyUtil
	{
		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
	{
		private static readonly Dictionary<SystemLanguage, Dictionary<string, string>> Translations = new Dictionary<SystemLanguage, Dictionary<string, string>>();

		public static void AddTranslation(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, params object[] args)
		{
			//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)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			SystemLanguage val = (SystemLanguage)10;
			LocalisationManager val2 = default(LocalisationManager);
			if (Service.Get<LocalisationManager>(ref val2) && val2.CurrentTranslator != null)
			{
				val = val2.CurrentTranslator.Language;
			}
			if (Translations.TryGetValue(val, out var value) && value.TryGetValue(key, out var value2))
			{
				return string.Format(value2, args);
			}
			if (Translations.TryGetValue((SystemLanguage)10, out var value3) && value3.TryGetValue(key, out var value4))
			{
				return string.Format(value4, args);
			}
			ArtisanMod.Logger.LogWarning((object)$"Translation key '{key}' not found for language '{val}'.");
			return key;
		}
	}
}
namespace Artisan.Source.Features.Spells.Patches
{
	[HarmonyPatch(typeof(ProjectilePush), "OnDestroy")]
	public static class ProjectilePushDamageCleanupPatch
	{
		private static void Prefix(ProjectilePush __instance)
		{
			ProjectilePushDamagePatch.ClearProjectile(__instance);
		}
	}
}
namespace Artisan.Source.Features.Spells.Context
{
	internal readonly struct ProjectilePushDamageContext
	{
		public static readonly ProjectilePushDamageContext Disabled = new ProjectilePushDamageContext(isEnabled: false, 0, affectPlayers: false, null, Vector3.zero);

		public bool IsEnabled { get; }

		public int DamageAmount { get; }

		public bool AffectPlayers { get; }

		public NetworkIdentity Caster { get; }

		public Vector3 ForceDirection { get; }

		public ProjectilePushDamageContext(bool isEnabled, int damageAmount, bool affectPlayers, NetworkIdentity caster, Vector3 forceDirection)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			IsEnabled = isEnabled;
			DamageAmount = damageAmount;
			AffectPlayers = affectPlayers;
			Caster = caster;
			ForceDirection = forceDirection;
		}

		public static ProjectilePushDamageContext Create(ProjectilePush projectile)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			Spell fieldValue = HarmonyUtil.GetFieldValue<Spell>(projectile, "OwnerSpell");
			NetworkIdentity fieldValue2 = HarmonyUtil.GetFieldValue<NetworkIdentity>(projectile, "Caster");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return Disabled;
			}
			if (((object)fieldValue).GetType() == typeof(PushSpell))
			{
				return new ProjectilePushDamageContext(ArtisanMod.Settings.Spells.Aero.Enabled.Value, ArtisanMod.Settings.Spells.Aero.Damage.Value, ArtisanMod.Settings.Spells.Aero.DamagePlayers.Value, fieldValue2, ((Component)projectile).transform.forward);
			}
			if (((object)fieldValue).GetType() == typeof(LevitationBlastSpell))
			{
				return new ProjectilePushDamageContext(ArtisanMod.Settings.Spells.TeleBlast.Enabled.Value, ArtisanMod.Settings.Spells.TeleBlast.Damage.Value, ArtisanMod.Settings.Spells.TeleBlast.DamagePlayers.Value, fieldValue2, ((Component)projectile).transform.forward);
			}
			return Disabled;
		}
	}
}
namespace Artisan.Features.Spells.Patches
{
	[HarmonyPatch(typeof(ProjectilePush), "OnTargetHit")]
	public static class ProjectilePushDamagePatch
	{
		private static readonly Dictionary<int, HashSet<uint>> DamagedTargetsByProjectile = new Dictionary<int, HashSet<uint>>();

		private static void Prefix(ProjectilePush __instance, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity)
		{
			if (CanProcessHit(__instance, target, targetRigidbody, targetIdentity))
			{
				ProjectilePushDamageContext context = ProjectilePushDamageContext.Create(__instance);
				if (context.IsEnabled && IsTargetPushable(__instance, target) && !WasRigidbodyAlreadyAffected(__instance, targetRigidbody) && TryMarkTargetDamaged(__instance, targetIdentity))
				{
					ApplyDamage(context, targetIdentity);
				}
			}
		}

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

		private static bool CanProcessHit(ProjectilePush projectile, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity)
		{
			if (NetworkServer.active && (Object)(object)projectile != (Object)null && ((NetworkBehaviour)projectile).isServer && (Object)(object)target != (Object)null && (Object)(object)targetRigidbody != (Object)null)
			{
				return (Object)(object)targetIdentity != (Object)null;
			}
			return false;
		}

		private static bool IsTargetPushable(ProjectilePush projectile, Collider target)
		{
			//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)
			LayerMask fieldValue = HarmonyUtil.GetFieldValue<LayerMask>(projectile, "pushableLayer");
			return ((1 << ((Component)target).gameObject.layer) & ((LayerMask)(ref fieldValue)).value) != 0;
		}

		private static bool WasRigidbodyAlreadyAffected(ProjectilePush projectile, Rigidbody targetRigidbody)
		{
			return HarmonyUtil.GetFieldValue<HashSet<Rigidbody>>(projectile, "affectedRigidbodies")?.Contains(targetRigidbody) ?? false;
		}

		private static void ApplyDamage(ProjectilePushDamageContext context, NetworkIdentity targetIdentity)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			NpcBehaviour val = default(NpcBehaviour);
			if (((Component)targetIdentity).TryGetComponent<NpcBehaviour>(ref val))
			{
				val.OnHit(context.DamageAmount, context.ForceDirection, false, context.Caster);
			}
			Pawn val2 = default(Pawn);
			if (context.AffectPlayers && ((Component)targetIdentity).TryGetComponent<Pawn>(ref val2) && !((Object)(object)val2.Hurtbox == (Object)null))
			{
				uint num = (((Object)(object)context.Caster != (Object)null) ? context.Caster.netId : 0u);
				val2.Hurtbox.OnHit(context.DamageAmount, 0f, context.ForceDirection, (StatusSO)null, false, false, false, num);
			}
		}

		private static bool TryMarkTargetDamaged(ProjectilePush projectile, NetworkIdentity targetIdentity)
		{
			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;
		}
	}
}
namespace Artisan.Features.Monsters.Patches
{
	[HarmonyPatch]
	public static class NpcHurtboxClientHitUiPatch
	{
		[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)
		{
			if ((Object)(object)__instance == (Object)null || !IsAnyHitUiEnabled())
			{
				return;
			}
			try
			{
				if (ArtisanMod.Settings.CombatUI.ShowMonsterHealthBars.Value)
				{
					ShowHealthBar(__instance);
				}
				if (ArtisanMod.Settings.CombatUI.ShowMonsterDamageIndicators.Value)
				{
					ShowDamageIndicator(__instance, damage);
				}
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[MonsterHitUI] Failed to render hit UI: " + ex));
			}
		}

		private static bool IsAnyHitUiEnabled()
		{
			if (!ArtisanMod.Settings.CombatUI.ShowMonsterHealthBars.Value)
			{
				return ArtisanMod.Settings.CombatUI.ShowMonsterDamageIndicators.Value;
			}
			return true;
		}

		private static void ShowHealthBar(NpcHurtbox hurtbox)
		{
			EnemyHealthBar enemyHealthBar = ((Component)hurtbox).GetComponent<EnemyHealthBar>();
			if ((Object)(object)enemyHealthBar == (Object)null)
			{
				enemyHealthBar = ((Component)hurtbox).gameObject.AddComponent<EnemyHealthBar>();
			}
			enemyHealthBar.EnsureInitialized();
			enemyHealthBar.ResetTimer();
			enemyHealthBar.UpdateHealthDisplay();
		}

		private static void ShowDamageIndicator(NpcHurtbox hurtbox, int damage)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			int damage2 = Mathf.Clamp(damage, 1, 9999);
			DamageTextFactory.Create(GetDamageIndicatorPosition(hurtbox), damage2);
		}

		private static Vector3 GetDamageIndicatorPosition(NpcHurtbox hurtbox)
		{
			//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)hurtbox).transform.position;
			NpcBehaviour val = default(NpcBehaviour);
			if (((Component)hurtbox).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));
		}
	}
}
namespace Artisan.Features.Monsters.UI
{
	public sealed class DamageText3D : MonoBehaviour
	{
		private TextMeshPro _textComponent;

		private Vector3 _baseWorldPosition;

		private float _timer = 1.5f;

		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)
			_baseWorldPosition = ((Component)this).transform.position;
			FaceCamera();
		}

		private void Update()
		{
			UpdatePosition();
			FaceCamera();
			UpdateLifetime();
			UpdateScale();
			UpdateAlpha();
		}

		public void Setup(float lifetime)
		{
			_timer = lifetime;
		}

		private void UpdatePosition()
		{
			//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)
			_floatHeight += Time.deltaTime * 0.8f;
			((Component)this).transform.position = _baseWorldPosition + Vector3.up * _floatHeight;
		}

		private void FaceCamera()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Camera.main == (Object)null))
			{
				((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position);
			}
		}

		private void UpdateLifetime()
		{
			_timer -= Time.deltaTime;
			if (_timer <= 0f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void UpdateScale()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			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;
			}
		}

		private void UpdateAlpha()
		{
			//IL_0015: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_textComponent == (Object)null))
			{
				Color color = ((Graphic)_textComponent).color;
				((Graphic)_textComponent).color = new Color(color.r, color.g, color.b, Mathf.Clamp01(_timer * 2f));
			}
		}
	}
	public static class DamageTextFactory
	{
		private readonly struct DamageTextStyle
		{
			public Color Color { get; }

			public float FontSize { get; }

			public float Lifetime { get; }

			private DamageTextStyle(Color color, float fontSize, float lifetime)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				Color = color;
				FontSize = fontSize;
				Lifetime = lifetime;
			}

			public static DamageTextStyle FromDamage(int damage)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				if (damage >= 50)
				{
					return new DamageTextStyle(Color.red, 6f, 3f);
				}
				if (damage >= 25)
				{
					return new DamageTextStyle(Color.yellow, 5f, 2f);
				}
				return new DamageTextStyle(new Color(1f, 0.5f, 0f), 4f, 1.5f);
			}
		}

		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_0063: 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)
			GameObject val = new GameObject("DamageText", new Type[2]
			{
				typeof(TextMeshPro),
				typeof(DamageText3D)
			});
			TextMeshPro component = val.GetComponent<TextMeshPro>();
			DamageText3D component2 = val.GetComponent<DamageText3D>();
			DamageTextStyle damageTextStyle = DamageTextStyle.FromDamage(damage);
			((TMP_Text)component).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component).text = $"-{damage}";
			((Graphic)component).color = damageTextStyle.Color;
			((TMP_Text)component).fontSize = damageTextStyle.FontSize;
			val.transform.position = position;
			component2.Setup(damageTextStyle.Lifetime);
		}
	}
	public sealed class EnemyHealthBar : 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);
				_targetFillAmount = ((num > 0) ? Mathf.Clamp01((float)num2 / (float)num) : 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			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 value = ArtisanMod.Settings.CombatUI.MonsterHealthBarExtraHeightOffset.Value;
				float num2 = Mathf.Clamp(num + value, 0.35f, 20f);
				if (!(Mathf.Abs(_worldOffset.y - num2) <= 0.01f))
				{
					_worldOffset = new Vector3(_worldOffset.x, num2, _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_0079: 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)
			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}";
				((Graphic)_healthText).color = ((num > 0 && (float)num2 / (float)num < 0.3f) ? Color.yellow : 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.UI
{
	[HarmonyPatch(typeof(UIInventory), "InitializeSlots")]
	public static class InventoryGridPatch
	{
		public static void Postfix(UIInventory __instance)
		{
			//IL_00a3: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || !ArtisanMod.Settings.Inventory.EnableExtendedSlots.Value)
			{
				return;
			}
			UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(__instance, "inventorySlots");
			if (fieldValue == null || fieldValue.Length == 0 || (Object)(object)fieldValue[0] == (Object)null)
			{
				return;
			}
			Transform parent = ((Component)fieldValue[0]).transform.parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (!((Object)(object)val == (Object)null))
			{
				DisableLayoutComponents(val);
				if (ArtisanMod.Settings.Inventory.HideInventoryBackground.Value)
				{
					HideInventoryBackground(__instance);
				}
				RectTransform component = ((Component)fieldValue[0]).GetComponent<RectTransform>();
				Vector2 slotSize = (Vector2)(((Object)(object)component != (Object)null) ? component.sizeDelta : new Vector2(36f, 36f));
				RepositionInventorySlotFrames(__instance, val, slotSize, fieldValue.Length);
				RepositionInventorySlots(fieldValue, slotSize);
				RepositionLeftHandSlotAndFrame(__instance, val, slotSize, fieldValue.Length);
				RepositionSelectedItemName(__instance, val, slotSize, fieldValue.Length);
				RepositionInputPrompts(__instance, val, slotSize, fieldValue.Length);
				LayoutRebuilder.MarkLayoutForRebuild(val);
			}
		}

		private static void DisableLayoutComponents(RectTransform container)
		{
			LayoutGroup[] components = ((Component)container).GetComponents<LayoutGroup>();
			for (int i = 0; i < components.Length; i++)
			{
				if ((Object)(object)components[i] != (Object)null)
				{
					((Behaviour)components[i]).enabled = false;
				}
			}
			ContentSizeFitter component = ((Component)container).GetComponent<ContentSizeFitter>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}

		private static void HideInventoryBackground(UIInventory inventory)
		{
			Transform val = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/InventoryFrame");
			if ((Object)(object)val == (Object)null)
			{
				ArtisanMod.Logger.LogWarning((object)"InventoryFrame was not found.");
			}
			else
			{
				((Component)val).gameObject.SetActive(false);
			}
		}

		private static int GetGridColumns()
		{
			return Mathf.Max(ArtisanMod.Settings.Inventory.GridColumns.Value, 3);
		}

		private static Vector2 CalculateSlotPosition(int index, Vector2 slotSize, int slotCount)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(ArtisanMod.Settings.Inventory.GridPositionX.Value, ArtisanMod.Settings.Inventory.GridPositionY.Value);
			int gridColumns = GetGridColumns();
			int num = Mathf.Min(gridColumns, slotCount);
			int num2 = Mathf.CeilToInt((float)slotCount / (float)gridColumns);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(ArtisanMod.Settings.Inventory.SlotSpacingX.Value, ArtisanMod.Settings.Inventory.SlotSpacingY.Value);
			if (ArtisanMod.Settings.Inventory.EnableAdaptiveGridPosition.Value)
			{
				float num3 = (float)(num - 1) * (slotSize.x + val2.x);
				float num4 = (float)(num2 - 1) * (slotSize.y + val2.y);
				float num5 = (float)(Mathf.Min(3, slotCount) - 1) * (slotSize.x + val2.x);
				val += new Vector2(num5 * 0.5f - num3, num4);
			}
			int num6 = index / gridColumns;
			int num7 = index % gridColumns;
			return val + new Vector2((float)num7 * (slotSize.x + val2.x), (float)(-num6) * (slotSize.y + val2.y));
		}

		private static float CalculateLeftHandSlotX(Vector2 slotSize, int slotCount)
		{
			//IL_0030: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(ArtisanMod.Settings.Inventory.SlotSpacingX.Value, ArtisanMod.Settings.Inventory.SlotSpacingY.Value);
			return CalculateSlotPosition(0, slotSize, slotCount).x - slotSize.x - val.x - ArtisanMod.Settings.Inventory.LeftHandSlotSpacingX.Value;
		}

		private static void MoveRectToInventoryXOnly(RectTransform rect, RectTransform targetParent, float targetX, Vector2 targetSize)
		{
			//IL_0014: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0036: 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)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rect == (Object)null) && !((Object)(object)targetParent == (Object)null))
			{
				Vector3 position = ((Transform)rect).position;
				Quaternion localRotation = ((Transform)rect).localRotation;
				((Transform)rect).SetParent((Transform)(object)targetParent, false);
				SetRectTransformCenteredAnchor(rect);
				Vector3 val = ((Transform)targetParent).InverseTransformPoint(position);
				rect.anchoredPosition = new Vector2(targetX, val.y);
				rect.sizeDelta = targetSize;
				((Transform)rect).localScale = Vector3.one;
				((Transform)rect).localRotation = localRotation;
			}
		}

		private static void SetRectTransformCenteredAnchor(RectTransform rect)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0.5f, 0.5f);
			rect.anchorMax = new Vector2(0.5f, 0.5f);
			rect.pivot = new Vector2(0.5f, 0.5f);
		}

		private static void RepositionInventorySlots(UIInventorySlot[] slots, Vector2 slotSize)
		{
			//IL_002d: 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)
			int num = slots.Length;
			for (int i = 0; i < num; i++)
			{
				UIInventorySlot val = slots[i];
				if (!((Object)(object)val == (Object)null))
				{
					RectTransform component = ((Component)val).GetComponent<RectTransform>();
					if (!((Object)(object)component == (Object)null))
					{
						SetRectTransformCenteredAnchor(component);
						component.anchoredPosition = CalculateSlotPosition(i, slotSize, num);
						((Transform)component).SetSiblingIndex(i);
					}
				}
			}
		}

		private static void CopyRectTransform(RectTransform source, RectTransform target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0031: 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)
			target.anchorMin = source.anchorMin;
			target.anchorMax = source.anchorMax;
			target.pivot = source.pivot;
			target.anchoredPosition = source.anchoredPosition;
			((Transform)target).localScale = Vector3.one;
			((Transform)target).localRotation = Quaternion.identity;
		}

		private static void RepositionLeftHandSlotAndFrame(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			UIInventorySlot fieldValue = HarmonyUtil.GetFieldValue<UIInventorySlot>(inventory, "leftHandSlot");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return;
			}
			RectTransform component = ((Component)fieldValue).GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null))
			{
				Transform obj = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/OffhandItem");
				RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					ArtisanMod.Logger.LogWarning((object)"OffhandItem frame was not found.");
					return;
				}
				float targetX = CalculateLeftHandSlotX(slotSize, slotCount);
				MoveRectToInventoryXOnly(component, container, targetX, slotSize + new Vector2(6f, 6f));
				((Transform)val).SetParent(((Transform)component).parent, false);
				CopyRectTransform(component, val);
				val.sizeDelta = component.sizeDelta + Vector2.one;
				((Component)val).gameObject.SetActive(true);
				((Transform)val).SetSiblingIndex(((Transform)component).GetSiblingIndex());
				((Transform)component).SetSiblingIndex(((Transform)val).GetSiblingIndex() + 1);
			}
		}

		private static Vector2 ConvertAnchoredPositionToTargetParent(RectTransform sourceParent, RectTransform targetParent, Vector2 sourceAnchoredPosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Transform)sourceParent).TransformPoint(Vector2.op_Implicit(sourceAnchoredPosition));
			Vector2 result = default(Vector2);
			RectTransformUtility.ScreenPointToLocalPointInRectangle(targetParent, RectTransformUtility.WorldToScreenPoint((Camera)null, val), (Camera)null, ref result);
			return result;
		}

		private static void RepositionInventorySlotFrames(UIInventory inventory, RectTransform slotContainer, Vector2 slotSize, int slotCount)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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)
			Transform obj = ((Component)inventory).transform.Find("InventoryPanel/BottomRight/InventoryContainer");
			RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				ArtisanMod.Logger.LogWarning((object)"InventoryContainer was not found.");
				return;
			}
			RectTransform[] orCreateInventorySlotFrames = GetOrCreateInventorySlotFrames((Transform)(object)val, slotCount);
			for (int i = 0; i < slotCount && i < orCreateInventorySlotFrames.Length; i++)
			{
				RectTransform val2 = orCreateInventorySlotFrames[i];
				if (!((Object)(object)val2 == (Object)null))
				{
					Vector2 sourceAnchoredPosition = CalculateSlotPosition(i, slotSize, slotCount);
					Vector2 anchoredPosition = ConvertAnchoredPositionToTargetParent(slotContainer, val, sourceAnchoredPosition);
					SetRectTransformCenteredAnchor(val2);
					val2.anchoredPosition = anchoredPosition;
					((Transform)val2).SetSiblingIndex(i);
					((Component)val2).gameObject.SetActive(true);
				}
			}
			for (int j = slotCount; j < orCreateInventorySlotFrames.Length; j++)
			{
				if ((Object)(object)orCreateInventorySlotFrames[j] != (Object)null)
				{
					((Component)orCreateInventorySlotFrames[j]).gameObject.SetActive(false);
				}
			}
		}

		private static RectTransform[] GetOrCreateInventorySlotFrames(Transform frameContainer, int slotCount)
		{
			List<RectTransform> list = new List<RectTransform>();
			for (int i = 0; i < frameContainer.childCount; i++)
			{
				Transform child = frameContainer.GetChild(i);
				if (!((Object)(object)child == (Object)null) && !(((Object)child).name != "InventoryItem"))
				{
					RectTransform component = ((Component)child).GetComponent<RectTransform>();
					if ((Object)(object)component != (Object)null)
					{
						list.Add(component);
					}
				}
			}
			if (list.Count == 0)
			{
				ArtisanMod.Logger.LogWarning((object)"No InventoryItem frame template was found.");
				return (RectTransform[])(object)new RectTransform[0];
			}
			RectTransform val = list[0];
			while (list.Count < slotCount)
			{
				RectTransform val2 = Object.Instantiate<RectTransform>(val, frameContainer);
				((Object)val2).name = "InventoryItem";
				list.Add(val2);
			}
			return list.ToArray();
		}

		private static void RepositionSelectedItemName(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI fieldValue = HarmonyUtil.GetFieldValue<TextMeshProUGUI>(inventory, "currentSelectedItemNameText");
			if (!((Object)(object)fieldValue == (Object)null))
			{
				RectTransform component = ((Component)fieldValue).GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null))
				{
					int num = Mathf.Min(GetGridColumns(), slotCount);
					float x = CalculateSlotPosition(0, slotSize, slotCount).x;
					float x2 = CalculateSlotPosition(num - 1, slotSize, slotCount).x;
					float num2 = (x + x2) * 0.5f;
					float num3 = Mathf.Abs(x2 - x) + slotSize.x;
					Vector2 val = CalculateSlotPosition(0, slotSize, slotCount);
					((Transform)component).SetParent((Transform)(object)container, false);
					SetRectTransformCenteredAnchor(component);
					component.anchoredPosition = new Vector2(num2, val.y + slotSize.y);
					component.sizeDelta = new Vector2(num3, component.sizeDelta.y);
					((TMP_Text)fieldValue).alignment = (TextAlignmentOptions)514;
					((TMP_Text)fieldValue).textWrappingMode = (TextWrappingModes)0;
					((TMP_Text)fieldValue).margin = Vector4.zero;
					((Transform)component).SetAsLastSibling();
				}
			}
		}

		private static void RepositionInputPrompts(UIInventory inventory, RectTransform container, Vector2 slotSize, int slotCount)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			CanvasGroup fieldValue = HarmonyUtil.GetFieldValue<CanvasGroup>(inventory, "scrollCanvasGroup");
			if (!((Object)(object)fieldValue == (Object)null))
			{
				Transform parent = ((Component)fieldValue).transform.parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if (!((Object)(object)val == (Object)null))
				{
					float num = CalculateLeftHandSlotX(slotSize, slotCount);
					((Transform)val).SetParent((Transform)(object)container, false);
					SetRectTransformCenteredAnchor(val);
					val.anchoredPosition = new Vector2(num - 75f, CalculateSlotPosition(slotCount - 1, slotSize, slotCount).y + 25f);
					((Transform)val).localScale = Vector3.one;
					((Transform)val).localRotation = Quaternion.identity;
					((Transform)val).SetAsLastSibling();
				}
			}
		}
	}
	public sealed class InventoryLockedSlotOverlay : MonoBehaviour
	{
		private const string OverlayName = "Artisan_LockedSlotOverlay";

		private const string LockIconName = "Artisan_LockedSlotIcon";

		private static readonly Vector2 OverlayInset = new Vector2(2f, 2f);

		private static readonly Vector2 LockIconSize = new Vector2(24f, 24f);

		private static readonly Vector2 LockIconOffset = new Vector2(0f, 4f);

		private static readonly Color OverlayColor = new Color(0.35f, 0.02f, 0.02f, 0.45f);

		private static readonly Color LockIconColor = new Color(0.86f, 0.9f, 0.92f, 0.96f);

		private GameObject overlayObject;

		private Image lockImage;

		public bool IsLocked { get; private set; }

		public void SetLocked(bool isLocked)
		{
			EnsureCreated();
			SyncOverlayRect();
			IsLocked = isLocked;
			if ((Object)(object)overlayObject != (Object)null)
			{
				overlayObject.SetActive(isLocked);
			}
		}

		private void EnsureCreated()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)overlayObject != (Object)null))
			{
				overlayObject = new GameObject("Artisan_LockedSlotOverlay", new Type[3]
				{
					typeof(RectTransform),
					typeof(CanvasGroup),
					typeof(Image)
				});
				overlayObject.transform.SetParent(((Component)this).transform, false);
				overlayObject.transform.SetAsLastSibling();
				Image component = overlayObject.GetComponent<Image>();
				((Graphic)component).color = OverlayColor;
				((Graphic)component).raycastTarget = false;
				CanvasGroup component2 = overlayObject.GetComponent<CanvasGroup>();
				component2.blocksRaycasts = false;
				component2.interactable = false;
				Sprite orCreate = TeleLockSpriteFactory.GetOrCreate();
				if ((Object)(object)orCreate == (Object)null)
				{
					ArtisanMod.Logger.LogWarning((object)"Tele-lock mesh sprite could not be created. Locked slot icon will be hidden.");
					overlayObject.SetActive(false);
					return;
				}
				GameObject val = new GameObject("Artisan_LockedSlotIcon", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val.transform.SetParent(overlayObject.transform, false);
				RectTransform component3 = val.GetComponent<RectTransform>();
				component3.anchorMin = new Vector2(0.5f, 0.5f);
				component3.anchorMax = new Vector2(0.5f, 0.5f);
				component3.pivot = new Vector2(0.5f, 0.5f);
				component3.sizeDelta = LockIconSize;
				component3.anchoredPosition = LockIconOffset;
				lockImage = val.GetComponent<Image>();
				lockImage.sprite = orCreate;
				((Graphic)lockImage).color = LockIconColor;
				((Graphic)lockImage).raycastTarget = false;
				lockImage.preserveAspect = true;
				overlayObject.SetActive(false);
			}
		}

		private void SyncOverlayRect()
		{
			//IL_0026: 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_0046: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)overlayObject == (Object)null))
			{
				RectTransform component = overlayObject.GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null))
				{
					component.anchorMin = Vector2.zero;
					component.anchorMax = Vector2.one;
					component.pivot = new Vector2(0.5f, 0.5f);
					component.offsetMin = OverlayInset;
					component.offsetMax = -OverlayInset;
					((Transform)component).localScale = Vector3.one;
					((Transform)component).localRotation = Quaternion.identity;
					overlayObject.transform.SetAsLastSibling();
				}
			}
		}
	}
	[HarmonyPatch]
	public static class InventoryLockedSlotOverlayPatch
	{
		[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[]>(inventoryUi, "inventorySlots");
			if (fieldValue2 == null)
			{
				return;
			}
			foreach (UIInventorySlot val in fieldValue2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					InventoryLockedSlotOverlay inventoryLockedSlotOverlay = ((Component)val).GetComponent<InventoryLockedSlotOverlay>();
					if ((Object)(object)inventoryLockedSlotOverlay == (Object)null)
					{
						inventoryLockedSlotOverlay = ((Component)val).gameObject.AddComponent<InventoryLockedSlotOverlay>();
					}
					bool locked = InventorySlotUpgradeService.IsEnabled() && !InventorySlotUpgradeService.IsSlotUnlocked(fieldValue, val.SlotIndex);
					inventoryLockedSlotOverlay.SetLocked(locked);
				}
			}
		}
	}
	[HarmonyPatch(typeof(UIInventory), "OnStartPawnAuthorityChanged")]
	public static class InventorySlotExpansionPatch
	{
		public static void Prefix(UIInventory __instance)
		{
			if ((Object)(object)__instance == (Object)null || !InventorySlotCapacityPatch.IsEnabled())
			{
				return;
			}
			UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(__instance, "inventorySlots");
			int maxInventorySlots = InventorySlotCapacityPatch.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;
				}
				((TMP_Text)GetSlotKeyText(component)).text = (j + 1).ToString();
				LayoutElement component2 = val2.GetComponent<LayoutElement>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.ignoreLayout = true;
				}
				array[j] = component;
			}
			HarmonyUtil.SetFieldValue(__instance, "inventorySlots", array);
		}

		private static TextMeshProUGUI GetSlotKeyText(UIInventorySlot slot)
		{
			if ((Object)(object)slot == (Object)null)
			{
				return null;
			}
			Transform val = ((Component)slot).transform.Find("Key");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			return ((Component)val).GetComponent<TextMeshProUGUI>();
		}
	}
	public static class TeleLockSpriteFactory
	{
		private const string MeshName = "SM_VFX_Tele_Lock_03";

		private static Sprite cachedSprite;

		public static Sprite GetOrCreate()
		{
			if ((Object)(object)cachedSprite != (Object)null)
			{
				return cachedSprite;
			}
			Mesh val = FindTeleLockMesh();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			cachedSprite = RenderMeshToSprite(val);
			if ((Object)(object)cachedSprite != (Object)null)
			{
				((Object)cachedSprite).name = "Artisan_TeleLockSprite";
			}
			return cachedSprite;
		}

		private static Mesh FindTeleLockMesh()
		{
			Mesh[] array = Resources.FindObjectsOfTypeAll<Mesh>();
			foreach (Mesh val in array)
			{
				if (!((Object)(object)val == (Object)null) && (((Object)val).name == "SM_VFX_Tele_Lock_03" || ((Object)val).name.Contains("SM_VFX_Tele_Lock_03")))
				{
					return val;
				}
			}
			ArtisanMod.Logger.LogWarning((object)"Could not find mesh asset: SM_VFX_Tele_Lock_03");
			return null;
		}

		private static void RemoveBlackBackground(Texture2D texture)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Color[] pixels = texture.GetPixels();
			for (int i = 0; i < pixels.Length; i++)
			{
				Color val = pixels[i];
				if (val.r < 0.03f && val.g < 0.03f && val.b < 0.03f)
				{
					pixels[i] = new Color(0f, 0f, 0f, 0f);
				}
			}
			texture.SetPixels(pixels);
			texture.Apply();
		}

		private static Sprite RenderMeshToSprite(Mesh mesh)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture val = null;
			GameObject val2 = null;
			GameObject val3 = null;
			Material val4 = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				val = new RenderTexture(128, 128, 24, (RenderTextureFormat)0);
				((Object)val).name = "Artisan_TeleLockRenderTexture";
				val.antiAliasing = 4;
				val.Create();
				val2 = new GameObject("Artisan_TeleLockRenderCamera");
				Camera obj = val2.AddComponent<Camera>();
				obj.clearFlags = (CameraClearFlags)2;
				obj.backgroundColor = new Color(0f, 0f, 0f, 0f);
				obj.orthographic = true;
				obj.orthographicSize = 0.7f;
				obj.nearClipPlane = 0.01f;
				obj.farClipPlane = 10f;
				((Component)obj).transform.position = new Vector3(0f, 0f, -3f);
				((Component)obj).transform.rotation = Quaternion.identity;
				obj.targetTexture = val;
				((Behaviour)obj).enabled = false;
				val3 = new GameObject("Artisan_TeleLockRenderMesh");
				MeshFilter obj2 = val3.AddComponent<MeshFilter>();
				MeshRenderer val5 = val3.AddComponent<MeshRenderer>();
				obj2.sharedMesh = mesh;
				Shader val6 = Shader.Find("Unlit/Color");
				if ((Object)(object)val6 == (Object)null)
				{
					val6 = Shader.Find("UI/Default");
				}
				if ((Object)(object)val6 == (Object)null)
				{
					val6 = Shader.Find("Sprites/Default");
				}
				val4 = new Material(val6);
				val4.color = Color.white;
				((Renderer)val5).sharedMaterial = val4;
				val3.transform.rotation = Quaternion.Euler(-90f, 0f, 180f);
				Bounds bounds = mesh.bounds;
				float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
				if (num > 0f)
				{
					val3.transform.localScale = Vector3.one * (1f / num);
				}
				val3.transform.position = -((Bounds)(ref bounds)).center * val3.transform.localScale.x;
				obj.Render();
				RenderTexture.active = val;
				Texture2D val7 = new Texture2D(128, 128, (TextureFormat)4, false);
				((Object)val7).name = "Artisan_TeleLockTexture";
				val7.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0);
				val7.Apply();
				RemoveBlackBackground(val7);
				return Sprite.Create(val7, new Rect(0f, 0f, (float)((Texture)val7).width, (float)((Texture)val7).height), new Vector2(0.5f, 0.5f), 128f);
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				if ((Object)(object)val3 != (Object)null)
				{
					Object.Destroy((Object)(object)val3);
				}
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
				if ((Object)(object)val != (Object)null)
				{
					val.Release();
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}
}
namespace Artisan.Features.Inventory.Services
{
	public static class InventorySlotUpgradeService
	{
		private const int VanillaSlotCount = 3;

		private const string UnlockedExtraSlotsKey = ".UNLOCKED_EXTRA_SLOTS";

		public static bool IsEnabled()
		{
			if (InventorySlotCapacityPatch.IsEnabled())
			{
				return ArtisanMod.Settings.Inventory.EnableSlotUpgrades.Value;
			}
			return false;
		}

		public static int GetMaxExtraSlots()
		{
			return Mathf.Max(0, InventorySlotCapacityPatch.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.Settings.Inventory.ExtraSlotBasePrice.Value);
			float num2 = Mathf.Max(1f, ArtisanMod.Settings.Inventory.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";
		}
	}
}
namespace Artisan.Features.Inventory.Patches
{
	[HarmonyPatch]
	public static class InventoryExtendedPersistencePatch
	{
		private static readonly HashSet<PawnInventory> RestoringInventories = new HashSet<PawnInventory>();

		[HarmonyPatch(typeof(PawnInventory), "ServerTryRestoreFromKvp")]
		[HarmonyPrefix]
		private static void ServerTryRestoreFromKvpPrefix(PawnInventory __instance, SaveManager save, string playerId)
		{
			if (!CanHandle(__instance, save, playerId))
			{
				return;
			}
			RestoringInventories.Add(__instance);
			try
			{
				DropSavedOverflowSlots(__instance, save, playerId);
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to drop saved overflow slots: " + ex.Message));
			}
		}

		[HarmonyPatch(typeof(PawnInventory), "ServerTryRestoreFromKvp")]
		[HarmonyPostfix]
		private static void ServerTryRestoreFromKvpPostfix(PawnInventory __instance, SaveManager save, string playerId)
		{
			if (!CanHandle(__instance, save, playerId))
			{
				return;
			}
			try
			{
				RestoreExtendedSlots(__instance, save, playerId);
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to restore extended slots: " + ex.Message));
			}
			finally
			{
				RestoringInventories.Remove(__instance);
			}
			__instance.ServerPersistInventory();
		}

		[HarmonyPatch(typeof(PawnInventory), "ServerSerializeToKvp")]
		[HarmonyPostfix]
		private static void ServerSerializeToKvpPostfix(PawnInventory __instance, SaveManager save, string playerId)
		{
			if (!CanHandle(__instance, save, playerId) || RestoringInventories.Contains(__instance))
			{
				return;
			}
			try
			{
				SerializeExtendedSlots(__instance, save, playerId);
			}
			catch (Exception ex)
			{
				ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed to serialize extended slots: " + ex.Message));
			}
		}

		private static bool CanHandle(PawnInventory inventory, SaveManager save, string playerId)
		{
			if ((Object)(object)inventory != (Object)null && (Object)(object)save != (Object)null && !string.IsNullOrEmpty(playerId))
			{
				return InventorySlotCapacityPatch.IsEnabled();
			}
			return false;
		}

		private static void SerializeExtendedSlots(PawnInventory inventory, SaveManager save, string playerId)
		{
			string keyPrefix = GetKeyPrefix(playerId);
			int maxInventorySlots = InventorySlotCapacityPatch.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))
			{
				for (int i = 0; i < maxInventorySlots; i++)
				{
					NetworkPuppetProp slotProp = GetSlotProp(inventory, i);
					methodInfo.Invoke(inventory, new object[3]
					{
						save,
						$"{keyPrefix}.S{i}",
						slotProp
					});
				}
			}
		}

		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_00ba: Unknown result type (might be due to invalid IL or missing references)
			string keyPrefix = GetKeyPrefix(playerId);
			int maxInventorySlots = InventorySlotCapacityPatch.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;
			}
			for (int i = 3; i < maxInventorySlots; i++)
			{
				if (i < inventory.Items.Count)
				{
					InventoryItem val = inventory.Items[i];
					if (!((InventoryItem)(ref val)).IsEmpty)
					{
						continue;
					}
				}
				NetworkPuppetProp val2 = TryRestoreProp(inventory, save, playerId, $"{keyPrefix}.S{i}", methodInfo);
				if (!((Object)(object)val2 == (Object)null))
				{
					if ((bool)methodInfo2.Invoke(inventory, new object[2]
					{
						i,
						(object)new InventoryItem(val2)
					}))
					{
						SetPropInInventory(val2, inventory);
					}
					else
					{
						DropRestoredOverflowProp(val2);
					}
				}
			}
			RestoreSelectedMainSlot(inventory, save, keyPrefix, maxInventorySlots);
			NormalizeRestoredInventoryProps(inventory);
		}

		private static void DropSavedOverflowSlots(PawnInventory inventory, SaveManager save, string playerId)
		{
			string keyPrefix = GetKeyPrefix(playerId);
			int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots();
			int num = default(int);
			if (!save.TryGetInt(keyPrefix + ".SLOT_COUNT", ref num) || num <= maxInventorySlots)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "TryRestoreProp", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(PawnInventory), "SerializeProp", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				return;
			}
			for (int i = maxInventorySlots; i < num; i++)
			{
				string text = $"{keyPrefix}.S{i}";
				NetworkPuppetProp val = TryRestoreProp(inventory, save, playerId, text, methodInfo);
				if (!((Object)(object)val == (Object)null))
				{
					DropRestoredOverflowProp(val);
					ClearSavedSlot(inventory, save, text, methodInfo2);
					ArtisanMod.Logger.LogInfo((object)$"Dropped overflow inventory item from saved slot {i + 1}.");
				}
			}
		}

		private static NetworkPuppetProp TryRestoreProp(PawnInventory inventory, SaveManager save, string playerId, string key, MethodInfo tryRestoreProp)
		{
			object[] array = new object[4] { save, key, playerId, null };
			if (!(bool)tryRestoreProp.Invoke(inventory, array))
			{
				return null;
			}
			object obj = array[3];
			return (NetworkPuppetProp)((obj is NetworkPuppetProp) ? obj : null);
		}

		private static void ClearSavedSlot(PawnInventory inventory, SaveManager save, string slotKey, MethodInfo serializeProp)
		{
			serializeProp.Invoke(inventory, new object[3] { save, slotKey, null });
		}

		private static NetworkPuppetProp GetSlotProp(PawnInventory inventory, int slotIndex)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (slotIndex < 0 || slotIndex >= inventory.Items.Count)
			{
				return null;
			}
			InventoryItem val = inventory.Items[slotIndex];
			if (!((InventoryItem)(ref val)).IsEmpty)
			{
				return ((InventoryItem)(ref val)).PropInstance;
			}
			return null;
		}

		private static void DropRestoredOverflowProp(NetworkPuppetProp prop)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)prop == (Object)null))
			{
				prop.IsShopItem = false;
				prop.ServerHandleDrop(true, default(Vector3));
				((Interactable)prop).RefreshLocalInteractable();
			}
		}

		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)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return;
			}
			int currentMainHandSlot = inventory.CurrentMainHandSlot;
			for (int i = 0; i < inventory.Items.Count; i++)
			{
				if (i != currentMainHandSlot)
				{
					NetworkPuppetProp slotProp = GetSlotProp(inventory, i);
					if ((Object)(object)slotProp != (Object)null)
					{
						SetPropInInventory(slotProp, inventory);
					}
				}
			}
			if ((Object)(object)GetSlotProp(inventory, currentMainHandSlot) != (Object)null)
			{
				inventory.SelectSlotWithMainHand(currentMainHandSlot);
			}
		}

		private static void RestoreSelectedMainSlot(PawnInventory inventory, SaveManager save, string keyPrefix, int maxSlots)
		{
			int num = default(int);
			if (save.TryGetInt(keyPrefix + ".MAIN", ref num))
			{
				num = Mathf.Clamp(num, 0, maxSlots - 1);
				if (!((Object)(object)GetSlotProp(inventory, num) == (Object)null))
				{
					inventory.SelectSlotWithMainHand(num);
				}
			}
		}

		private static string GetKeyPrefix(string playerId)
		{
			return "PLAYER." + playerId + ".INV";
		}
	}
	[HarmonyPatch(typeof(UIInventory), "Update")]
	public static class InventoryExtendedHotkeysPatch
	{
		private static void Postfix(UIInventory __instance)
		{
			if (!InventorySlotCapacityPatch.IsEnabled())
			{
				return;
			}
			PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory");
			if ((Object)(object)fieldValue == (Object)null)
			{
				return;
			}
			int maxInventorySlots = InventorySlotCapacityPatch.GetMaxInventorySlots();
			for (int i = 3; i < maxInventorySlots; i++)
			{
				if (InventorySlotUpgradeService.IsSlotUnlocked(fieldValue, i))
				{
					InputAction slotAction = InventorySlotRebindSettings.GetSlotAction(i);
					if (slotAction != null && slotAction.WasPressedThisFrame())
					{
						fieldValue.CmdSelectSlotWithMainHand(i);
						break;
					}
				}
			}
		}
	}
	[HarmonyPatch]
	public static class InventoryLockedSlotPatch
	{
		[HarmonyPatch(typeof(PawnInventory), "SelectSlotWithMainHand")]
		[HarmonyPrefix]
		private static bool SelectSlotWithMainHandPrefix(PawnInventory __instance, int slotIndex)
		{
			return IsSlotSelectionAllowed(__instance, slotIndex);
		}

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

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

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

		[HarmonyPatch(typeof(PawnInventory), "UserCode_CmdCycleSlot__Boolean")]
		[HarmonyPrefix]
		private static bool CmdCycleSlotPrefix(PawnInventory __instance, bool cycleForward)
		{
			if (!InventorySlotUpgradeService.IsEnabled())
			{
				return true;
			}
			return TryCycleToUnlockedSlot(__instance, cycleForward);
		}

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

		[HarmonyPatch(typeof(PawnInventory), "ServerTryPickup")]
		[HarmonyPrefix]
		private static bool ServerTryPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop, int preferredSlotIndex, ref bool __result)
		{
			if (!InventorySlotUpgradeService.IsEnabled())
			{
				return true;
			}
			__result = TryPickupInUnlockedSpace(__instance, prop, preferredSlotIndex);
			return false;
		}

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

		[HarmonyPatch(typeof(UIInventory), "OnSlotDrop")]
		[HarmonyPrefix]
		private static bool OnSlotDropPrefix(UIInventory __instance, UIInventorySlot targetSlot)
		{
			PawnInventory playerInventory = GetPlayerInventory(__instance);
			UIInventorySlot draggedSlot = GetDraggedSlot(__instance);
			if (!IsDropBlocked(playerInventory, targetSlot, draggedSlot))
			{
				return true;
			}
			__instance.StopDrag();
			return false;
		}

		[HarmonyPatch(typeof(UIInventory), "OnDragHoverEnter")]
		[HarmonyPrefix]
		private static bool OnDragHoverEnterPrefix(UIInventory __instance, UIInventorySlot slot)
		{
			return !IsLockedInventorySlot(GetPlayerInventory(__instance), slot);
		}

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

		[HarmonyPatch(typeof(PawnInventory), "TryRestoreIfPossible")]
		[HarmonyPostfix]
		private static void TryRestoreIfPossiblePostfix(PawnInventory __instance)
		{
			DropItemsFromLockedSlots(__instance);
		}

		[HarmonyPatch(typeof(NetworkPuppetProp), "ShowTooltip")]
		[HarmonyPrefix]
		private static bool NetworkPuppetPropShowTooltipPrefix(NetworkPuppetProp __instance, NetworkIdentity identity)
		{
			if (!InventorySlotUpgradeService.IsEnabled())
			{
				return true;
			}
			PawnInventory inventory = GetInventory(identity);
			if ((Object)(object)inventory == (Object)null || HasAvailablePickupSpace(inventory))
			{
				return true;
			}
			ShowInventoryFullTooltip(__instance);
			return false;
		}

		[HarmonyPatch(typeof(PropIngredient), "CustomTooltipAction")]
		[HarmonyPostfix]
		private static void PropIngredientCustomTooltipActionPostfix(PropIngredient __instance, Interactable interactable, NetworkIdentity identity)
		{
			if (!InventorySlotUpgradeService.IsEnabled())
			{
				return;
			}
			PawnInventory inventory = GetInventory(identity);
			if (!((Object)(object)inventory == (Object)null) && !HasAvailablePickupSpace(inventory))
			{
				NetworkPuppetProp val = ResolvePuppetProp(__instance, interactable);
				if (!((Object)(object)val == (Object)null))
				{
					ShowIngredientInventoryFullTooltip(val);
				}
			}
		}

		public static void DropItemsFromLockedSlots(PawnInventory inventory)
		{
			if (!NetworkServer.active || (Object)(object)inventory == (Object)null || !InventorySlotUpgradeService.IsEnabled())
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < inventory.Items.Count; i++)
			{
				if (!InventorySlotUpgradeService.IsSlotUnlocked(inventory, i) && DropItemFromLockedSlot(inventory, i))
				{
					flag = true;
				}
			}
			if (flag)
			{
				inventory.ServerPersistInventory();
			}
		}

		private static bool DropItemFromLockedSlot(PawnInventory inventory, int slotIndex)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (slotIndex < 0 || slotIndex >= inventory.Items.Count)
			{
				return false;
			}
			InventoryItem val = inventory.Items[slotIndex];
			if (((InventoryItem)(ref val)).IsEmpty || val.propNetId == 0)
			{
				return false;
			}
			NetworkPuppetProp val2 = inventory.SvGetPropFromNetId(val.propNetId);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			if (!inventory.ServerRemoveItem(val.propNetId))
			{
				return false;
			}
			val2.IsShopItem = false;
			val2.ServerHandleDrop(true, default(Vector3));
			((Interactable)val2).RefreshLocalInteractable();
			return true;
		}

		private static bool IsSlotSelectionAllowed(PawnInventory inventory, int slotIndex)
		{
			return InventorySlotUpgradeService.IsSlotUnlocked(inventory, slotIndex);
		}

		private static bool TryCycleToUnlockedSlot(PawnInventory inventory, bool cycleForward)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return false;
			}
			int unlockedSlotCount = InventorySlotUpgradeService.GetUnlockedSlotCount(inventory);
			if (unlockedSlotCount <= 0)
			{
				return false;
			}
			int num = inventory.CurrentMainHandSlot;
			for (int i = 0; i < unlockedSlotCount; i++)
			{
				num = GetNextSlotIndex(num, unlockedSlotCount, cycleForward);
				if (InventorySlotUpgradeService.IsSlotUnlocked(inventory, num))
				{
					inventory.SelectSlotWithMainHand(num);
					return false;
				}
			}
			return false;
		}

		private static int GetNextSlotIndex(int currentSlot, int slotCount, bool cycleForward)
		{
			int num = (cycleForward ? (currentSlot - 1) : (currentSlot + 1));
			if (num < 0)
			{
				return slotCount - 1;
			}
			if (num >= slotCount)
			{
				return 0;
			}
			return num;
		}

		private static bool TryPickupInUnlockedSpace(PawnInventory inventory, NetworkPuppetProp prop, int preferredSlotIndex)
		{
			if ((Object)(object)inventory == (Object)null || (Object)(object)prop == (Object)null || !prop.CanPickedUpBy(((NetworkBehaviour)inventory).netIdentity))
			{
				return false;
			}
			int slotIndex = ResolvePreferredSlot(inventory, preferredSlotIndex);
			if (TryPickupIntoSlot(inventory, prop, slotIndex))
			{
				return true;
			}
			if (TryPickupIntoLeftHand(inventory, prop))
			{
				return true;
			}
			int firstUnlockedEmptySlot = InventorySlotUpgradeService.GetFirstUnlockedEmptySlot(inventory);
			if (firstUnlockedEmptySlot >= 0)
			{
				return inventory.ServerTryPickupInventorySlotOnly(prop, firstUnlockedEmptySlot);
			}
			return false;
		}

		private static int ResolvePreferredSlot(PawnInventory inventory, int preferredSlotIndex)
		{
			if (preferredSlotIndex != -1)
			{
				return preferredSlotIndex;
			}
			return inventory.CurrentMainHandSlot;
		}

		private static bool TryPickupIntoSlot(PawnInventory inventory, NetworkPuppetProp prop, int slotIndex)
		{
			if (InventorySlotUpgradeService.IsSlotUnlocked(inventory, slotIndex))
			{
				return inventory.ServerTryPickupInventorySlotOnly(prop, slotIndex);
			}
			return false;
		}

		private static bool TryPickupIntoLeftHand(PawnInventory inventory, NetworkPuppetProp prop)
		{
			PawnPropInteractions propInteractions = GetPropInteractions(inventory);
			if ((Object)(object)propInteractions == (Object)null || (Object)(object)propInteractions.NetworkCurrentLeftHandNetworkProp != (Object)null)
			{
				return false;
			}
			prop.ServerHandleHeld(propInteractions, false);
			return true;
		}

		private static bool HasAvailablePickupSpace(PawnInventory inventory)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return false;
			}
			if (InventorySlotUpgradeService.GetFirstUnlockedEmptySlot(inventory) >= 0)
			{
				return true;
			}
			PawnPropInteractions propInteractions = GetPropInteractions(inventory);
			if ((Object)(object)propInteractions != (Object)null)
			{
				return (Object)(object)propInteractions.NetworkCurrentLeftHandNetworkProp == (Object)null;
			}
			return false;
		}

		private static bool IsDropBlocked(PawnInventory inventory, UIInventorySlot targetSlot, UIInventorySlot draggedSlot)
		{
			if ((Object)(object)inventory == (Object)null || (Object)(object)targetSlot == (Object)null)
			{
				return false;
			}
			if (!IsLockedInventorySlot(inventory, targetSlot))
			{
				return IsLockedInventorySlot(inventory, draggedSlot);
			}
			return true;
		}

		private static bool IsLockedInventorySlot(PawnInventory inventory, UIInventorySlot slot)
		{
			if ((Object)(object)inventory == (Object)null || (Object)(object)slot == (Object)null || slot.IsHandSlot)
			{
				return false;
			}
			return !InventorySlotUpgradeService.IsSlotUnlocked(inventory, slot.SlotIndex);
		}

		private static PawnInventory GetInventory(NetworkIdentity identity)
		{
			if (!((Object)(object)identity == (Object)null))
			{
				return ((Component)identity).GetComponent<PawnInventory>();
			}
			return null;
		}

		private static PawnInventory GetPlayerInventory(UIInventory inventoryUi)
		{
			if (!((Object)(object)inventoryUi == (Object)null))
			{
				return HarmonyUtil.GetFieldValue<PawnInventory>(inventoryUi, "_playerInventory");
			}
			return null;
		}

		private static UIInventorySlot GetDraggedSlot(UIInventory inventoryUi)
		{
			if (!((Object)(object)inventoryUi == (Object)null))
			{
				return HarmonyUtil.GetFieldValue<UIInventorySlot>(inventoryUi, "_draggedSlot");
			}
			return null;
		}

		private static PawnPropInteractions GetPropInteractions(PawnInventory inventory)
		{
			if ((Object)(object)inventory == (Object)null)
			{
				return null;
			}
			PawnPropInteractions fieldValue = HarmonyUtil.GetFieldValue<PawnPropInteractions>(inventory, "propInteractions");
			if (!((Object)(object)fieldValue != (Object)null))
			{
				return ((Component)inventory).GetComponent<PawnPropInteractions>();
			}
			return fieldValue;
		}

		private static NetworkPuppetProp ResolvePuppetProp(PropIngredient ingredient, Interactable interactable)
		{
			NetworkPuppetProp val = (NetworkPuppetProp)(object)((interactable is NetworkPuppetProp) ? interactable : null);
			if (val != null)
			{
				return val;
			}
			if (!((Object)(object)ingredient == (Object)null))
			{
				return ((Component)ingredient).GetComponent<NetworkPuppetProp>();
			}
			return null;
		}

		private static void ShowInventoryFullTooltip(NetworkPuppetProp prop)
		{
			UIManager instance = UIManager.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.uiTooltip == (Object)null) && !((Object)(object)prop == (Object)null))
			{
				string text = prop.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")";
				instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, prop.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, prop.IsGrabable, false, (string)null, (InputTarget)9, true, false);
			}
		}

		private static void ShowIngredientInve