Decompiled source of RunicDisplayStands v1.2.4

RunicDisplayStands.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RunicDisplayStands")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RunicDisplayStands")]
[assembly: AssemblyTitle("RunicDisplayStands")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RunicDisplayStands
{
	public class ContainerBridge : MonoBehaviour
	{
		private static ContainerBridge _opened;

		private static StandVirtualContainer _virtualContainer;

		private static readonly FieldInfo ContainerInventoryField = AccessTools.Field(typeof(Container), "m_inventory");

		private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null);

		private Inventory _inventory;

		private ItemStand _itemStand;

		private ArmorStand _armorStand;

		private bool _refreshing;

		internal static ContainerBridge Opened => _opened;

		public static ContainerBridge GetOrCreate(GameObject go)
		{
			ContainerBridge component = go.GetComponent<ContainerBridge>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			component = go.AddComponent<ContainerBridge>();
			component.Initialize();
			return component;
		}

		private void Initialize()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			_itemStand = ((Component)this).GetComponent<ItemStand>();
			_armorStand = ((Component)this).GetComponent<ArmorStand>();
			int num = ((!((Object)(object)_armorStand != (Object)null)) ? 1 : ArmorStandAdapter.GetSlotCount(_armorStand));
			string text = (((Object)(object)_itemStand != (Object)null) ? _itemStand.GetHoverName() : "$piece_armorstand");
			_inventory = new Inventory(text, (Sprite)null, num, 1);
			Inventory inventory = _inventory;
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged));
		}

		public bool OpenAsContainer(Humanoid user)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (!(user is Player) || (Object)(object)InventoryGui.instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_opened != (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)this).GetComponent<ZNetView>();
			if (component != null)
			{
				component.ClaimOwnership();
			}
			RefreshInventory();
			_opened = this;
			if ((Object)(object)_virtualContainer == (Object)null)
			{
				GameObject val = new GameObject("RunicDisplayStandsVirtualContainer");
				val.SetActive(false);
				_virtualContainer = val.AddComponent<StandVirtualContainer>();
			}
			((Container)_virtualContainer).m_name = _inventory.GetName();
			((Container)_virtualContainer).m_width = _inventory.GetWidth();
			((Container)_virtualContainer).m_height = _inventory.GetHeight();
			ContainerInventoryField.SetValue(_virtualContainer, _inventory);
			((Component)_virtualContainer).transform.SetParent(((Component)this).transform, false);
			InventoryGui.instance.Show((Container)(object)_virtualContainer, 1);
			SetUseEquipButton(useEquip: true);
			return true;
		}

		public bool TakeOne(Humanoid user)
		{
			RefreshInventory();
			ItemData itemAt = _inventory.GetItemAt(0, 0);
			if (itemAt == null)
			{
				return false;
			}
			ItemData val = itemAt.Clone();
			val.m_stack = 1;
			if (!user.GetInventory().CanAddItem(val, 1))
			{
				return false;
			}
			user.GetInventory().AddItem(val);
			_inventory.RemoveOneItem(itemAt);
			PushInventoryToStand();
			return true;
		}

		internal void SwapEquip()
		{
			if ((Object)(object)_armorStand != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				ArmorStandAdapter.SwapWithPlayer(_armorStand, Player.m_localPlayer);
			}
			else if ((Object)(object)_itemStand != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				ItemStandAdapter.SwapWithPlayer(_itemStand, Player.m_localPlayer);
			}
			RefreshInventory();
		}

		internal static void Closed()
		{
			if (!((Object)(object)_opened == (Object)null))
			{
				_opened.PushInventoryToStand();
				_opened = null;
				SetUseEquipButton(useEquip: false);
				if ((Object)(object)_virtualContainer != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_virtualContainer).gameObject);
					_virtualContainer = null;
				}
			}
		}

		private void RefreshInventory()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			_refreshing = true;
			_inventory.RemoveAll();
			if ((Object)(object)_itemStand != (Object)null)
			{
				ItemData placedItem = ItemStandAdapter.GetPlacedItem(_itemStand);
				if (placedItem != null)
				{
					_inventory.AddItem(placedItem);
				}
			}
			else
			{
				List<ItemData> placedItems = ArmorStandAdapter.GetPlacedItems(_armorStand);
				for (int i = 0; i < placedItems.Count; i++)
				{
					if (placedItems[i] != null)
					{
						_inventory.AddItem(placedItems[i], new Vector2i(i, 0));
					}
				}
			}
			InventoryChangedMethod.Invoke(_inventory, null);
			_refreshing = false;
		}

		private void OnInventoryChanged()
		{
			if (!_refreshing)
			{
				PushInventoryToStand();
			}
		}

		private void PushInventoryToStand()
		{
			if ((Object)(object)_itemStand != (Object)null)
			{
				List<ItemData> allItems = _inventory.GetAllItems();
				ItemStandAdapter.SetPlacedItem(_itemStand, (allItems.Count > 0) ? allItems[0] : null);
			}
			else
			{
				List<ItemData> allItems2 = _inventory.GetAllItems();
				ArmorStandAdapter.SetPlacedItems(_armorStand, allItems2);
			}
		}

		internal static void SetUseEquipButton(bool useEquip)
		{
			if (!((Object)(object)InventoryGui.instance == (Object)null) && !((Object)(object)InventoryGui.instance.m_stackAllButton == (Object)null))
			{
				Button stackAllButton = InventoryGui.instance.m_stackAllButton;
				((Component)stackAllButton).gameObject.SetActive(useEquip);
				TMP_Text componentInChildren = ((Component)stackAllButton).GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = (useEquip ? "Use/equip" : "$inventory_stackall");
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
	[HarmonyPriority(0)]
	internal static class InventoryGui_UpdateContainer_Stand_Patch
	{
		private static void Postfix()
		{
			if ((Object)(object)ContainerBridge.Opened != (Object)null)
			{
				ContainerBridge.SetUseEquipButton(useEquip: true);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnStackAll")]
	[HarmonyPriority(800)]
	internal static class InventoryGui_OnStackAll_Stand_Patch
	{
		private static bool Prefix()
		{
			if ((Object)(object)ContainerBridge.Opened == (Object)null)
			{
				return true;
			}
			ContainerBridge.Opened.SwapEquip();
			return false;
		}
	}
	internal sealed class StandVirtualContainer : Container
	{
	}
	[HarmonyPatch(typeof(Container), "IsOwner")]
	internal static class VirtualContainer_IsOwner_Patch
	{
		private static bool Prefix(Container __instance, ref bool __result)
		{
			if (!(__instance is StandVirtualContainer))
			{
				return true;
			}
			__result = (Object)(object)ContainerBridge.Opened != (Object)null;
			return false;
		}
	}
	[HarmonyPatch(typeof(Container), "SetInUse")]
	internal static class VirtualContainer_SetInUse_Patch
	{
		private static bool Prefix(Container __instance)
		{
			return !(__instance is StandVirtualContainer);
		}
	}
	[HarmonyPatch(typeof(Container), "StackAll")]
	internal static class VirtualContainer_StackAll_Patch
	{
		private static bool Prefix(Container __instance)
		{
			if (!(__instance is StandVirtualContainer))
			{
				return true;
			}
			ContainerBridge.Opened?.SwapEquip();
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	internal static class InventoryGui_Hide_Stand_Patch
	{
		private static void Prefix()
		{
			ContainerBridge.Closed();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
	internal static class InventoryGui_CloseContainer_Stand_Patch
	{
		private static void Prefix()
		{
			ContainerBridge.Closed();
		}
	}
	internal static class ItemDataSerializer
	{
		internal static byte[] Serialize(ItemData item)
		{
			//IL_0011: 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_0028: 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)
			//IL_0039: Expected O, but got Unknown
			if (item == null)
			{
				return Array.Empty<byte>();
			}
			Inventory val = new Inventory("RunicDisplayStands", (Sprite)null, 1, 1);
			ItemData val2 = item.Clone();
			val2.m_stack = 1;
			val.AddItem(val2, new Vector2i(0, 0));
			ZPackage val3 = new ZPackage();
			val.Save(val3);
			return val3.GetArray();
		}

		internal static ItemData Deserialize(byte[] bytes)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (bytes == null || bytes.Length == 0)
			{
				return null;
			}
			try
			{
				Inventory val = new Inventory("RunicDisplayStands", (Sprite)null, 1, 1);
				val.Load(new ZPackage(bytes));
				List<ItemData> allItems = val.GetAllItems();
				if (allItems.Count == 0)
				{
					return null;
				}
				ItemData obj = allItems[0];
				obj.m_stack = 1;
				return obj;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not restore complete stand item data; using vanilla fallback. " + ex.Message));
				}
				return null;
			}
		}
	}
	internal static class ConfigSync
	{
		private const string RpcName = "RunicDisplayStands_ConfigSync";

		private static readonly List<ConfigEntryBase> _synced = new List<ConfigEntryBase>();

		private static bool _rpcRegistered;

		public static void RegisterSyncedConfig(ConfigEntryBase entry)
		{
			_synced.Add(entry);
			EnsureRpcRegistered();
		}

		internal static void EnsureRpcRegistered()
		{
			if (!_rpcRegistered && ZRoutedRpc.instance != null)
			{
				_rpcRegistered = true;
				ZRoutedRpc.instance.Register<string>("RunicDisplayStands_ConfigSync", (Action<long, string>)OnConfigReceived);
			}
		}

		public static void NotifyNewConnection(ZNetPeer peer)
		{
			EnsureRpcRegistered();
			if (_rpcRegistered && ZNet.instance.IsServer())
			{
				string text = Serialize();
				ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "RunicDisplayStands_ConfigSync", new object[1] { text });
			}
		}

		private static void OnConfigReceived(long sender, string payload)
		{
			if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer())
			{
				Deserialize(payload);
				Plugin.RebuildStandPrefabSet();
				Plugin.Log.LogInfo((object)"Received admin config from server; local Stand Prefabs list updated.");
			}
		}

		private static string Serialize()
		{
			List<string> list = new List<string>();
			foreach (ConfigEntryBase item in _synced)
			{
				list.Add($"{item.Definition.Key}={item.BoxedValue}");
			}
			return string.Join("|", list);
		}

		private static void Deserialize(string payload)
		{
			string[] array = payload.Split('|');
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '=' }, 2);
				if (array2.Length != 2)
				{
					continue;
				}
				foreach (ConfigEntryBase item in _synced)
				{
					if (item.Definition.Key == array2[0])
					{
						item.BoxedValue = array2[1];
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNet_Awake_ConfigSync_Patch
	{
		private static void Postfix()
		{
			ConfigSync.EnsureRpcRegistered();
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class ZNet_OnNewConnection_Patch
	{
		private static void Postfix(ZNetPeer peer)
		{
			ConfigSync.NotifyNewConnection(peer);
		}
	}
	internal static class ArmorStandAdapter
	{
		public const int SlotCount = 6;

		public const int SlotHelmet = 0;

		public const int SlotChest = 1;

		public const int SlotLegs = 2;

		public const int SlotCape = 3;

		public const int SlotWeapon = 4;

		public const int SlotShield = 5;

		private static readonly FieldInfo SlotsField = AccessTools.Field(typeof(ArmorStand), "m_slots");

		private static readonly MethodInfo CanAttachMethod = AccessTools.Method(typeof(ArmorStand), "CanAttach", (Type[])null, (Type[])null);

		public static int GetSlotCount(ArmorStand stand)
		{
			return ((ICollection)SlotsField.GetValue(stand)).Count;
		}

		public static List<ItemData> GetPlacedItems(ArmorStand stand)
		{
			int slotCount = GetSlotCount(stand);
			List<ItemData> list = new List<ItemData>((IEnumerable<ItemData>)(object)new ItemData[slotCount]);
			ZNetView component = ((Component)stand).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return list;
			}
			for (int i = 0; i < slotCount; i++)
			{
				string attachedItem = stand.GetAttachedItem(i);
				if (string.IsNullOrEmpty(attachedItem))
				{
					continue;
				}
				ItemData val = ItemDataSerializer.Deserialize(component.GetZDO().GetByteArray(ItemDataKey(i), (byte[])null));
				if (val != null)
				{
					list[i] = val;
					continue;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(attachedItem);
				if (!((Object)(object)itemPrefab == (Object)null))
				{
					ItemData val2 = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
					val2.m_variant = component.GetZDO().GetInt(VariantKey(i), 0);
					val2.m_stack = 1;
					list[i] = val2;
				}
			}
			return list;
		}

		public static void SetPlacedItems(ArmorStand stand, IList<ItemData> items)
		{
			ZNetView component = ((Component)stand).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			int slotCount = GetSlotCount(stand);
			ItemData[] array = MapItemsToSlots(stand, items);
			for (int i = 0; i < slotCount; i++)
			{
				ItemData val = array[i];
				if (val != null)
				{
					string name = ((Object)val.m_dropPrefab).name;
					component.GetZDO().Set(ItemKey(i), name);
					component.GetZDO().Set(VariantKey(i), val.m_variant, false);
					component.GetZDO().Set(ItemDataKey(i), ItemDataSerializer.Serialize(val));
					component.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { i, name, val.m_variant });
				}
				else
				{
					component.GetZDO().Set(ItemKey(i), "");
					component.GetZDO().Set(VariantKey(i), 0, false);
					component.GetZDO().Set(ItemDataKey(i), Array.Empty<byte>());
					component.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { i, "", 0 });
				}
			}
		}

		public static void SwapWithPlayer(ArmorStand stand, Player player)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> equippedItems = inventory.GetEquippedItems();
			int slotCount = GetSlotCount(stand);
			ItemData[] array = (ItemData[])(object)new ItemData[slotCount];
			List<ItemData> list = equippedItems.ToList();
			ItemData val = FindFirstHotbarItem(inventory, StandSlotValidator.WeaponTypes);
			ItemData val2 = FindFirstHotbarItem(inventory, StandSlotValidator.ShieldTypes);
			if (val != null && !list.Contains(val))
			{
				list.Add(val);
			}
			if (val2 != null && !list.Contains(val2))
			{
				list.Add(val2);
			}
			foreach (ItemData item in list)
			{
				for (int i = 0; i < slotCount; i++)
				{
					if (array[i] == null && CanAttachAt(stand, i, item))
					{
						array[i] = item;
						break;
					}
				}
			}
			List<ItemData> placedItems = GetPlacedItems(stand);
			ItemData[] array2 = array;
			foreach (ItemData val3 in array2)
			{
				if (val3 != null && val3.m_equipped)
				{
					((Humanoid)player).UnequipItem(val3, false);
				}
			}
			array2 = array;
			foreach (ItemData val4 in array2)
			{
				if (val4 != null)
				{
					inventory.RemoveItem(val4);
				}
			}
			SetPlacedItems(stand, array);
			for (int k = 0; k < slotCount; k++)
			{
				ItemData val5 = placedItems[k];
				if (val5 != null)
				{
					if (!inventory.CanAddItem(val5, val5.m_stack))
					{
						ItemDrop.DropItem(val5, val5.m_stack, ((Component)player).transform.position, ((Component)player).transform.rotation);
						continue;
					}
					inventory.AddItem(val5);
					((Humanoid)player).EquipItem(val5, false);
				}
			}
		}

		private static int ItemKey(int index)
		{
			return StringExtensionMethods.GetStableHashCode($"{index}_item");
		}

		private static int VariantKey(int index)
		{
			return StringExtensionMethods.GetStableHashCode($"{index}_variant");
		}

		private static int ItemDataKey(int index)
		{
			return StringExtensionMethods.GetStableHashCode($"RunicDisplayStands_itemdata_{index}");
		}

		private static bool CanAttachAt(ArmorStand stand, int index, ItemData item)
		{
			IList list = (IList)SlotsField.GetValue(stand);
			return (bool)CanAttachMethod.Invoke(stand, new object[2]
			{
				list[index],
				item
			});
		}

		public static ItemData[] MapItemsToSlots(ArmorStand stand, IEnumerable<ItemData> items)
		{
			int slotCount = GetSlotCount(stand);
			ItemData[] array = (ItemData[])(object)new ItemData[slotCount];
			foreach (ItemData item in items)
			{
				if (item == null)
				{
					continue;
				}
				for (int i = 0; i < slotCount; i++)
				{
					if (array[i] == null && CanAttachAt(stand, i, item))
					{
						array[i] = item;
						break;
					}
				}
			}
			return array;
		}

		private static ItemData FindFirstHotbarItem(Inventory inv, HashSet<ItemType> types)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 8; i++)
			{
				ItemData itemAt = inv.GetItemAt(i, 0);
				if (itemAt != null && types.Contains(itemAt.m_shared.m_itemType))
				{
					return itemAt;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ItemStand), "Interact")]
	internal static class ItemStand_Interact_Patch
	{
		private static bool Prefix(ItemStand __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			if (!Plugin.StandPrefabSet.Contains(((Object)((Component)__instance).gameObject).name.Replace("(Clone)", "")))
			{
				return true;
			}
			if (__1)
			{
				return true;
			}
			if (__2 || IsTakeOneHeld())
			{
				ContainerBridge orCreate = ContainerBridge.GetOrCreate(((Component)__instance).gameObject);
				__result = orCreate.TakeOne(__0);
			}
			else
			{
				ContainerBridge orCreate2 = ContainerBridge.GetOrCreate(((Component)__instance).gameObject);
				__result = orCreate2.OpenAsContainer(__0);
			}
			return false;
		}

		private static bool IsTakeOneHeld()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.CfgTakeOneKey.Value;
			return ((KeyboardShortcut)(ref value)).IsDown();
		}
	}
	[HarmonyPatch(typeof(Switch), "Interact")]
	internal static class ArmorStand_Switch_Interact_Patch
	{
		private static bool Prefix(Switch __instance, Humanoid __0, bool __1, ref bool __result)
		{
			ArmorStand componentInParent = ((Component)__instance).GetComponentInParent<ArmorStand>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return true;
			}
			if (!Plugin.StandPrefabSet.Contains(((Object)((Component)componentInParent).gameObject).name.Replace("(Clone)", "")))
			{
				return true;
			}
			if (__1)
			{
				return true;
			}
			ContainerBridge orCreate = ContainerBridge.GetOrCreate(((Component)componentInParent).gameObject);
			__result = orCreate.OpenAsContainer(__0);
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "GetElement")]
	[HarmonyPriority(800)]
	internal static class InventoryGrid_GetElement_Bounds_Patch
	{
		private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements");

		private static bool Prefix(int x, int y, int width, InventoryGrid __instance)
		{
			if (!(ElementsField?.GetValue(__instance) is IList list))
			{
				return true;
			}
			long num = (long)y * (long)width + x;
			if (x >= 0 && y >= 0 && width > 0 && num >= 0 && num < list.Count)
			{
				return true;
			}
			return false;
		}
	}
	internal static class ItemStandAdapter
	{
		private static readonly MethodInfo GetOrientationMethod = AccessTools.Method(typeof(ItemStand), "GetOrientation", (Type[])null, (Type[])null);

		private static readonly int ItemDataKey = StringExtensionMethods.GetStableHashCode("RunicDisplayStands_itemdata");

		public static ItemData GetPlacedItem(ItemStand stand)
		{
			ZNetView component = ((Component)stand).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return null;
			}
			string attachedItem = stand.GetAttachedItem();
			if (string.IsNullOrEmpty(attachedItem))
			{
				return null;
			}
			ItemData val = ItemDataSerializer.Deserialize(component.GetZDO().GetByteArray(ItemDataKey, (byte[])null));
			if (val != null)
			{
				return val;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(attachedItem);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return null;
			}
			ItemData obj = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
			obj.m_quality = component.GetZDO().GetInt(ZDOVars.s_quality, 1);
			obj.m_variant = component.GetZDO().GetInt(ZDOVars.s_variant, 0);
			obj.m_stack = 1;
			return obj;
		}

		public static void SetPlacedItem(ItemStand stand, ItemData item)
		{
			ZNetView component = ((Component)stand).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				if (item == null)
				{
					component.GetZDO().Set(ZDOVars.s_item, "");
					component.GetZDO().Set(ZDOVars.s_variant, 0, false);
					component.GetZDO().Set(ZDOVars.s_quality, 1, false);
					component.GetZDO().Set(ItemDataKey, Array.Empty<byte>());
					int orientation = GetOrientation(stand);
					component.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { "", 0, 1, orientation });
				}
				else
				{
					string name = ((Object)item.m_dropPrefab).name;
					component.GetZDO().Set(ZDOVars.s_item, name);
					component.GetZDO().Set(ZDOVars.s_quality, item.m_quality, false);
					component.GetZDO().Set(ZDOVars.s_variant, item.m_variant, false);
					component.GetZDO().Set(ItemDataKey, ItemDataSerializer.Serialize(item));
					int orientation2 = GetOrientation(stand);
					component.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { name, item.m_variant, item.m_quality, orientation2 });
				}
			}
		}

		private static int GetOrientation(ItemStand stand)
		{
			return (int)GetOrientationMethod.Invoke(stand, null);
		}

		public static void SwapWithPlayer(ItemStand stand, Player player)
		{
			ItemData placedItem = GetPlacedItem(stand);
			if (placedItem != null)
			{
				Inventory inventory = ((Humanoid)player).GetInventory();
				if (inventory.CanAddItem(placedItem, placedItem.m_stack))
				{
					SetPlacedItem(stand, null);
					inventory.AddItem(placedItem);
					((Humanoid)player).EquipItem(placedItem, false);
				}
			}
		}
	}
	internal static class StandSlotValidator
	{
		public static readonly HashSet<ItemType> WeaponTypes = new HashSet<ItemType>
		{
			(ItemType)3,
			(ItemType)14,
			(ItemType)22,
			(ItemType)4
		};

		public static readonly HashSet<ItemType> ShieldTypes = new HashSet<ItemType> { (ItemType)5 };

		public static bool IsValidForItemStand(ItemData item)
		{
			return item != null;
		}

		public static bool IsValidForArmorSlot(ItemData item, int slotIndex)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0076: 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)
			if (item == null)
			{
				return false;
			}
			return slotIndex switch
			{
				0 => (int)item.m_shared.m_itemType == 6, 
				1 => (int)item.m_shared.m_itemType == 7, 
				2 => (int)item.m_shared.m_itemType == 11, 
				3 => (int)item.m_shared.m_itemType == 17, 
				4 => WeaponTypes.Contains(item.m_shared.m_itemType), 
				5 => ShieldTypes.Contains(item.m_shared.m_itemType), 
				_ => false, 
			};
		}
	}
	[BepInPlugin("chazman.RunicDisplayStands", "RunicDisplayStands", "1.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "chazman.RunicDisplayStands";

		public const string PluginName = "RunicDisplayStands";

		public const string PluginVersion = "1.2.4";

		public static Plugin Instance;

		internal static ManualLogSource Log;

		public static ConfigEntry<string> CfgStandPrefabs;

		public static ConfigEntry<bool> CfgGamepadSupport;

		public static ConfigEntry<KeyboardShortcut> CfgTakeOneKey;

		public static HashSet<string> StandPrefabSet = new HashSet<string>();

		private readonly Harmony _harmony = new Harmony("chazman.RunicDisplayStands");

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CfgStandPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Admin", "Stand Prefabs", "itemstand,itemstandh,ArmorStand", new ConfigDescription("Comma separated list of prefab names that should be treated as item/armor stands.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					IsAdminOnly = true
				}
			}));
			CfgGamepadSupport = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Gamepad Support", true, "Enable controller-friendly interact prompts and alt-take binding.");
			CfgTakeOneKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Take One Item Key", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Hold this while interacting with a stand to take a single item instead of opening it.");
			RebuildStandPrefabSet();
			CfgStandPrefabs.SettingChanged += delegate
			{
				RebuildStandPrefabSet();
			};
			ConfigSync.RegisterSyncedConfig((ConfigEntryBase)(object)CfgStandPrefabs);
			_harmony.PatchAll();
			Log.LogInfo((object)"RunicDisplayStands v1.2.4 loaded.");
		}

		internal static void RebuildStandPrefabSet()
		{
			StandPrefabSet = (from s in CfgStandPrefabs.Value.Split(',')
				select s.Trim() into s
				where s.Length > 0
				select s).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
		}
	}
	public class ConfigurationManagerAttributes
	{
		public bool IsAdminOnly;
	}
}