Decompiled source of MySix ArmorStandSwap v1.0.2

MySix.ArmorStandSwap.dll

Decompiled 22 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using MySix.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace MySix
{
	internal static class SuiteVersion
	{
		public const string Value = "1.0.2";
	}
}
namespace MySix.ArmorStandSwap
{
	[HarmonyPatch(typeof(ArmorStand), "UseItem")]
	public static class UseItemPatch
	{
		private struct Exchange
		{
			public int Slot;

			public ItemData FromStand;

			public ItemData FromPlayer;
		}

		public static Setting<bool> Enabled;

		private static readonly FieldRef<ArmorStand, List<ArmorStandSlot>> Slots = AccessTools.FieldRefAccess<ArmorStand, List<ArmorStandSlot>>("m_slots");

		private static readonly FieldRef<ArmorStand, ZNetView> NView = AccessTools.FieldRefAccess<ArmorStand, ZNetView>("m_nview");

		private static readonly FieldRef<ArmorStand, ItemData> QueuedItem = AccessTools.FieldRefAccess<ArmorStand, ItemData>("m_queuedItem");

		private static readonly FieldRef<ArmorStand, int> QueuedSlot = AccessTools.FieldRefAccess<ArmorStand, int>("m_queuedSlot");

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

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

		private static readonly string[] WornFields = new string[7] { "m_helmetItem", "m_chestItem", "m_legItem", "m_shoulderItem", "m_utilityItem", "m_rightItem", "m_leftItem" };

		private static readonly Dictionary<string, FieldRef<Humanoid, ItemData>> WornRefs = WornFields.ToDictionary((string n) => n, (string n) => AccessTools.FieldRefAccess<Humanoid, ItemData>(n));

		private static bool Prefix(ArmorStand __instance, Switch caller, Humanoid user, ItemData item, ref bool __result)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled == null || !Enabled.Value || item != null)
			{
				return true;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false))
			{
				return true;
			}
			ZNetView val2 = NView.Invoke(__instance);
			if ((Object)(object)val2 == (Object)null || !val2.IsValid())
			{
				return true;
			}
			if (!val2.IsOwner())
			{
				val2.ClaimOwnership();
			}
			__result = Swap(__instance, val, val2);
			return false;
		}

		private static bool Swap(ArmorStand stand, Player player, ZNetView nview)
		{
			List<ArmorStandSlot> list = Slots.Invoke(stand);
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Exchange> list2 = new List<Exchange>();
			List<ItemData> list3 = new List<ItemData>();
			for (int i = 0; i < list.Count; i++)
			{
				ItemData val = ReadAttachedItem(stand, nview, i);
				ItemData val2 = FindWornFor(player, stand, list[i], list3);
				if (val != null || val2 != null)
				{
					if (val2 != null)
					{
						list3.Add(val2);
					}
					list2.Add(new Exchange
					{
						Slot = i,
						FromStand = val,
						FromPlayer = val2
					});
				}
			}
			if (list2.Count == 0)
			{
				((Character)player).Message((MessageType)2, "Nothing to swap", 0, (Sprite)null, false);
				return false;
			}
			if (list2.Count((Exchange p) => p.FromStand != null) > inventory.GetEmptySlots())
			{
				((Character)player).Message((MessageType)2, "Not enough room in your inventory to swap", 0, (Sprite)null, false);
				return false;
			}
			int num = 0;
			foreach (Exchange item in list2)
			{
				ItemData val3 = null;
				if (item.FromStand != null)
				{
					if (inventory.AddItem(item.FromStand))
					{
						val3 = item.FromStand;
					}
					if (val3 == null)
					{
						((Character)player).Message((MessageType)2, "Not enough room in your inventory to swap", 0, (Sprite)null, false);
						break;
					}
					stand.DestroyAttachment(item.Slot);
				}
				if (item.FromPlayer != null)
				{
					QueuedItem.Invoke(stand) = item.FromPlayer;
					QueuedSlot.Invoke(stand) = item.Slot;
					UpdateAttach.Invoke(stand, null);
				}
				if (val3 != null)
				{
					((Humanoid)player).EquipItem(val3, true);
				}
				num++;
			}
			if (num > 0)
			{
				CorePlugin.Log.LogInfo((object)$"ArmorStandSwap: swapped {num} slot(s)");
				((Character)player).Message((MessageType)2, (num == 1) ? "Swapped 1 piece" : $"Swapped {num} pieces", 0, (Sprite)null, false);
			}
			return num > 0;
		}

		private static ItemData ReadAttachedItem(ArmorStand stand, ZNetView nview, int slot)
		{
			int attachedItem = stand.GetAttachedItem(slot);
			if (attachedItem == 0)
			{
				return null;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(attachedItem) : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				CorePlugin.Log.LogWarning((object)$"ArmorStandSwap: unknown item {attachedItem} on stand slot {slot}; leaving it alone");
				return null;
			}
			ItemData obj = val2.m_itemData.Clone();
			obj.m_dropPrefab = val;
			ItemDrop.LoadFromZDO(obj, nview.GetZDO(), slot);
			obj.m_stack = 1;
			obj.m_equipped = false;
			return obj;
		}

		private static ItemData FindWornFor(Player player, ArmorStand stand, ArmorStandSlot slot, List<ItemData> alreadyClaimed)
		{
			foreach (ItemData item in Worn(player))
			{
				if (item != null && !alreadyClaimed.Contains(item) && (bool)CanAttach.Invoke(stand, new object[2] { slot, item }))
				{
					return item;
				}
			}
			return null;
		}

		private static IEnumerable<ItemData> Worn(Player player)
		{
			string[] wornFields = WornFields;
			foreach (string key in wornFields)
			{
				yield return WornRefs[key].Invoke((Humanoid)(object)player);
			}
		}
	}
	[BepInPlugin("com.mysix.armorstandswap", "MySix Armor Stand Swap", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ArmorStandSwapPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.mysix.armorstandswap";

		public const string PluginName = "MySix Armor Stand Swap";

		public const string PluginVersion = "1.0.2";

		private const int RequiredCoreApi = 1;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (CorePlugin.RequireApi("MySix Armor Stand Swap", 1))
			{
				UseItemPatch.Enabled = Settings.Register<bool>("MySix Armor Stand Swap", ((BaseUnityPlugin)this).Config.Bind<bool>("ArmorStandSwap", "Enabled", true, "Pressing E on an armour stand with empty hands swaps your whole outfit with the stand's. Using a hotbar item on the stand (keys 1-8) is unchanged."), (Scope)0, (string)null);
				_harmony = new Harmony("com.mysix.armorstandswap");
				_harmony.PatchAll(typeof(ArmorStandSwapPlugin).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"MySix Armor Stand Swap 1.0.2 loaded");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}