Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ZenItemStands v1.0.2
plugins/ZenItemStands.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using Zen; using Zen.Compatibility; using Zen.Lib; using Zen.Lib.Config; using ZenItemStands.Compatibility; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenItemStands")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ZenItemStands")] [assembly: AssemblyCopyright("Copyright \ufffd 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ZenItemStands { internal class ArmorStandInventory : StandInventory { private ArmorStand _stand; private static readonly StringBuilder Sb = new StringBuilder(); protected override void Awake() { if (!((Component)this).TryGetComponent<ArmorStand>(ref _stand)) { throw new Exception("ArmorStand component not found on " + ((Object)this).name); } SetupInventory(_stand.m_name, _stand.m_slots.Count, 1); ((Component)this).GetComponentInChildren<Switch>().m_name = _stand.m_name; base.Awake(); } public override void ShowErrorMessage() { ((Character)Player.m_localPlayer).Message((MessageType)2, "$piece_armorstand_cantattach", 0, (Sprite)null); } protected override bool IsSameType(ItemData armorItem, ItemData compareItem) { ArmorStandSlot slot = GetSlot(armorItem); if (slot != null) { return _stand.CanAttach(slot, compareItem); } return false; } private ArmorStandSlot? GetSlot(ItemData item) { return ((IEnumerable<ArmorStandSlot>)_stand.m_slots).FirstOrDefault((Func<ArmorStandSlot, bool>)((ArmorStandSlot slot) => slot.m_currentItemName == ItemDataExt.GetName(item))); } private ItemData? GetAttachedItemData(int index) { //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_0043: Unknown result type (might be due to invalid IL or missing references) string attachedItem = _stand.GetAttachedItem(index); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(14, 2, ref flag); if (flag) { val.AppendLiteral("Index: "); val.AppendFormatted<int>(index); val.AppendLiteral(" Item: "); val.AppendFormatted(attachedItem); } Logging<Plugin>.Debug(val, 0); return GetItemDataFromZDO(attachedItem, index); } protected override bool IsStandInventoryDiff() { //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_0024: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) int num = 0; bool flag = default(bool); for (int i = 0; i < _stand.m_slots.Count; i++) { ItemData attachedItemData = GetAttachedItemData(i); if (attachedItemData == null) { continue; } if (!InventoryExt.HaveItemData(((VirtualInventory)this).Inventory, attachedItemData)) { InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(11, 1, ref flag); if (flag) { val.AppendLiteral("Diff Item: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemData)); } Logging<Plugin>.Info(val, 0); return true; } num++; } bool num2 = num != ((VirtualInventory)this).Inventory.NrOfItems(); if (!num2) { InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(41, 1, ref flag); if (flag) { val.AppendLiteral("Container and stand are identical: "); val.AppendFormatted<int>(num); val.AppendLiteral(" items"); } Logging<Plugin>.Debug(val, 0); } return num2; } protected override bool CanAttach(ItemData item, bool ignoreExisting) { int index; return CanAttach(item, out index, ignoreExisting); } private bool CanAttach(ItemData item, out int index, bool ignoreExisting) { index = -1; for (int i = 0; i < _stand.m_slots.Count; i++) { if (CanAttachAt(i)) { index = i; return true; } } return false; bool CanAttachAt(int num) { //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) ArmorStandSlot val = _stand.m_slots[num]; if (!_stand.CanAttach(val, item)) { return false; } if (!ignoreExisting && _stand.HaveAttachment(num)) { return false; } ItemType itemType = item.m_shared.m_itemType; if (((int)itemType == 7 || (int)itemType == 11) ? true : false) { return true; } foreach (Transform item2 in item.m_dropPrefab.transform) { if (((Object)item2).name.StartsWith("attach")) { return true; } } return false; } } protected override bool CanSwap(ItemData externItem, out ItemData swapItem) { if (CanAttach(externItem, ignoreExisting: true)) { foreach (ItemData allItem in ((VirtualInventory)this).Inventory.GetAllItems()) { if (IsSameType(allItem, externItem)) { swapItem = allItem; return true; } } } swapItem = null; return false; } public override void SwapEquip() { Inventory inventory = ((VirtualInventory)this).Inventory; Player localPlayer = Player.m_localPlayer; List<ItemData> equippedItems = ((Humanoid)localPlayer).GetInventory().GetEquippedItems(); if (((Humanoid)localPlayer).m_hiddenLeftItem != null) { equippedItems.Add(((Humanoid)localPlayer).m_hiddenLeftItem); } if (((Humanoid)localPlayer).m_hiddenRightItem != null) { equippedItems.Add(((Humanoid)localPlayer).m_hiddenRightItem); } ItemData[] array = inventory.GetAllItems().ToArray(); foreach (ItemData standItem in array) { EquipItemSwap(localPlayer, standItem); } ((Humanoid)localPlayer).HideHandItems(false, false); Inventory inventory2 = ((Humanoid)localPlayer).GetInventory(); foreach (ItemData item in equippedItems) { if (inventory2.ContainsItem(item) && CanAttach(item, ignoreExisting: false)) { ((Humanoid)localPlayer).UnequipItem(item, false); inventory.MoveItemToThis(inventory2, item); } } } private bool AttachItem(ItemData item) { if (!CanAttach(item, out var index, ignoreExisting: false)) { return false; } base.Nview.ClaimOwnership(); ZDO zDO = base.Nview.GetZDO(); zDO.Set(index + "_item", ((Object)item.m_dropPrefab).name); ItemDrop.SaveToZDO(index, item, zDO); return true; } protected override void UpdateVisualFromContainer() { //IL_0055: 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_0072: 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) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (IsStandInventoryDiff()) { Logging<Plugin>.Info("Updating visuals and slot data", 0); ClearArmorStand(); int num = ((VirtualInventory)this).Inventory.GetAllItems().Count(AttachItem); _stand.UpdateVisual(); Transform transform = ((Component)this).transform; _stand.m_effects.Create(transform.position, transform.rotation, (Transform)null, 1f, -1); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(29, 2, ref flag); if (flag) { val.AppendFormatted("ArmorStand"); val.AppendLiteral(" loaded "); val.AppendFormatted<int>(num); val.AppendLiteral(" items from container"); } Logging<Plugin>.Info(val, 0); } } private void ClearArmorStand() { for (int i = 0; i < _stand.m_slots.Count; i++) { if (base.Nview.IsOwner()) { base.Nview.GetZDO().Set(i + "_item", string.Empty); } _stand.SetVisualItem(i, string.Empty, 0); } _stand.UpdateSupports(); } protected override void LoadInventory() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info("Fill inventory from slots", 0); bool flag = default(bool); for (int i = 0; i < _stand.m_slots.Count; i++) { if (!_stand.HaveAttachment(i)) { continue; } ItemData attachedItemData = GetAttachedItemData(i); if (attachedItemData != null) { ((VirtualInventory)this).Inventory.AddItem(attachedItemData); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(46, 1, ref flag); if (flag) { val.AppendLiteral("Added item to container from ArmorStand slot: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemData)); } Logging<Plugin>.Info(val, 0); } } } protected override bool IsStackAllButtonVisible() { if (Configs.EnableArmorStandEquipButton.Value) { return !Conflict.IsConflict; } return false; } protected override bool CanHoldToEquip() { if (!Conflict.IsConflict) { return Configs.EnableArmorStandHoldToEquip.Value; } return false; } public void ValidatePose() { if (Configs.EnableArmorStandPoseChange.Value && !_stand.HasChestAndLegItem()) { _stand.ResetPose(); } } public override string GetHoverText() { Sb.Clear(); Sb.Append(base.GetHoverText()); if (WardAccessExt.CanAccessWard((MonoBehaviour)(object)this, false) && Configs.EnableArmorStandPoseChange.Value && _stand.HasChestAndLegItem()) { Sb.Append(StringExt.Localize("\n" + UI.PromptInteractAlt + " $hud_changeorientation")); } return Sb.ToString(); } } internal static class ArmorStandExt { public static void ResetPose(this ArmorStand armorStand) { if (armorStand.m_pose != 0) { armorStand.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetPose", new object[1] { 0 }); } } public static void NextPose(this ArmorStand armorStand) { armorStand.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetPose", new object[1] { (armorStand.m_pose + 1) % armorStand.m_poseCount }); } public static bool HasChestAndLegItem(this ArmorStand armorStand) { bool flag = false; bool flag2 = false; for (int i = 0; i < armorStand.m_slots.Count; i++) { string attachedItem = armorStand.GetAttachedItem(i); if (!Utility.IsNullOrWhiteSpace(attachedItem)) { ItemDrop component = ObjectDB.instance.GetItemPrefab(attachedItem).GetComponent<ItemDrop>(); if (ItemDataExt.IsItemType(component.m_itemData, (ItemType)7)) { flag = true; } if (ItemDataExt.IsItemType(component.m_itemData, (ItemType)11)) { flag2 = true; } if (flag && flag2) { return true; } } } return false; } } [HarmonyPatch] internal static class ArmorStandPatch { [HarmonyPatch(typeof(ArmorStand), "SetPose")] private static class ArmorStandSetPose { [UsedImplicitly] private static void Prefix(ref bool effect) { effect = false; } [UsedImplicitly] private static void Postfix(ArmorStand __instance) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) __instance.UpdateSupports(); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(8, 2, ref flag); if (flag) { val.AppendFormatted("SetPose"); val.AppendLiteral(" index: "); val.AppendFormatted<int>(__instance.m_pose); } Logging<Plugin>.Info(val, 0); } } [HarmonyPostfix] [HarmonyPatch(typeof(ArmorStand), "Awake")] private static void ArmorStand_Awake(ArmorStand __instance) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory _) && !Configs.EnableArmorStandPoseChange.Value) { __instance.ResetPose(); } } [HarmonyPostfix] [HarmonyPatch(typeof(Switch), "GetHoverText")] private static void ArmorStand_Switch_GetHoverText(Switch __instance, ref string __result) { ArmorStand componentInParent = ((Component)__instance).GetComponentInParent<ArmorStand>(); if (Object.op_Implicit((Object)(object)componentInParent) && ((MonoBehaviour)(object)componentInParent).HasStandInventory(out StandInventory si)) { __result = si.GetHoverText(); } } [HarmonyPostfix] [HarmonyPatch(typeof(ArmorStand), "UpdateSupports")] private static void ArmorStand_UpdateSupports(ArmorStand __instance) { if (!Configs.EnableArmorStandPoseChange.Value) { return; } if (__instance.m_supports.Count == 0) { Logging<Plugin>.Warning((object)"m_supports is length 0 when it should be at least 1, aborting.", 0); return; } ArmorStandSupport obj = __instance.m_supports[0]; int pose = __instance.m_pose; foreach (GameObject support in obj.m_supports) { support.SetActive(pose == 0); } ((Component)((Component)__instance).transform.Find("New/Lod1/ArmorStand")).gameObject.SetActive(pose < 4); } [HarmonyPrefix] [HarmonyPatch(typeof(Switch), "Interact")] private static void ArmorStand_Switch_Interact(Switch __instance, Humanoid character, bool hold, bool alt, ref bool __result, ref bool __runOriginal) { ArmorStand componentInParent = ((Component)__instance).GetComponentInParent<ArmorStand>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !((MonoBehaviour)(object)componentInParent).HasStandInventory(out StandInventory si)) { return; } __runOriginal = false; if (!hold) { __result = true; } if (alt && Configs.EnableArmorStandPoseChange.Value) { if (!hold) { componentInParent.NextPose(); } } else { si.Open(); Game.instance.IncrementPlayerStat((PlayerStatType)25, 1f); } } [HarmonyPrefix] [HarmonyPatch(typeof(ArmorStand), "UseItem")] private static void ArmorStand_UseItem(ArmorStand __instance, ref bool __result, ref bool __runOriginal) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory si) && !si.CanUseHotbarItem()) { __runOriginal = false; __result = false; } } [HarmonyPostfix] [HarmonyPatch(typeof(ArmorStand), "RPC_DropItemByName")] private static void ArmorStand_RPC_DropItemByName(ArmorStand __instance) { if (((MonoBehaviour)(object)__instance).IsThisStandOpen()) { InventoryGui.instance.Hide(); } } } internal static class Configs { private const string SECTION_GENERAL = "General"; public static readonly ConfigEntry<StringList> StandPrefabNames; public static readonly ConfigEntry<bool> EnableHotbarUseItem; private const string SECTION_ARMORSTAND = "Piece: ArmorStand"; public static readonly ConfigEntry<bool> EnableArmorStandPoseChange; public static readonly ConfigEntry<bool> EnableArmorStandHoldToEquip; public static readonly ConfigEntry<bool> EnableArmorStandEquipButton; public static readonly ConfigEntry<bool> EnableArmorStandAmericanSpelling; private const string SECTION_ITEMSTAND = "Piece: ItemStand"; public static readonly ConfigEntry<bool> EnableItemStandEquipButton; public static readonly ConfigEntry<bool> ShowItemOnStandName; static Configs() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0046: Expected O, but got Unknown StringList val = new StringList(); ((List<string>)val).Add("itemstand"); ((List<string>)val).Add("itemstandh"); ((List<string>)val).Add("ArmorStand"); ((List<string>)val).Add("Placeable_HardRock"); StandPrefabNames = Config.Define<StringList>(true, "General", "Stand Prefabs", val, "List of all the prefabs that are item stands or armor stands.\nThese prefabs must have an ItemStand or ArmorStand component attached to them."); EnableHotbarUseItem = Config.Define<bool>(true, "General", "Enable Hotbar Use Item", false, "If enabled you can also use traditional 1-8 hotbar buttons to assign items to stands (Vanilla: true)"); EnableArmorStandPoseChange = Config.Define<bool>(true, "Piece: ArmorStand", "Enable Pose Changing", false, "Enable changing poses of armor stands. NOTE: Stand must have chest and legs armor."); EnableArmorStandHoldToEquip = Config.Define<bool>(true, "Piece: ArmorStand", "Enable Hold To Equip", false, "Should (Hold to equip) be available on Armor Stands hover text?"); EnableArmorStandEquipButton = Config.Define<bool>(true, "Piece: ArmorStand", "Enable Use/Equip Button", true, "Enable the use/equip button on armor stands to quickly swap equipped gear."); EnableArmorStandAmericanSpelling = Config.Define<bool>(false, "Piece: ArmorStand", "American Spelling", true, "Change the spelling to 'Armor Stand' instead of 'Armour Stand'\r\n[Restart required for changes to take effect]"); EnableItemStandEquipButton = Config.Define<bool>(true, "Piece: ItemStand", "Enable Use/Equip Button", true, "Enable the use/equip button on item stands to quickly swap equipped gear."); ShowItemOnStandName = Config.Define<bool>(true, "Piece: ItemStand", "Show Item Name", true, "Show the name of the item on the stand in the hover text (Vanilla: true)\r\n[ZenHoverItem overrides this option]"); } } internal static class ItemStandExt { public static bool HasOrientations(this ItemStand itemStand) { return itemStand.m_orientationSettings.Count > 1; } } [HarmonyPatch] internal static class PetRock { [HarmonyPrefix] [HarmonyPatch(typeof(Pet), "GetHoverText")] private static void Pet_GetHoverText(Pet __instance, ref string __result, ref bool __runOriginal) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory _)) { __runOriginal = false; if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)__instance, false)) { __result = __instance.m_tameable.GetHoverName(); __result += StringExt.Localize("\n" + UI.PromptInteract + " $hud_pet"); } else { __result += __instance.m_tameable.GetHoverText(); __result = __result.Replace(StringExt.Localize(">] $hud_pet"), StringExt.Localize(">] $hud_pet ($msg_hold_equip_hover)")); } } } [HarmonyPrefix] [HarmonyPatch(typeof(Pet), "Interact")] private static void Pet_Interact(Pet __instance, Humanoid user, bool alt, bool hold, ref bool __result, ref bool __runOriginal) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory si)) { __runOriginal = false; if (alt) { __instance.m_tameable.Interact(user, false, true); } else if (hold) { si.SetLabel(__instance.m_tameable.GetHoverName()); __instance.m_itemStand.Interact(user, false, false); } else { __instance.m_tameable.Interact(user, false, false); } } } } internal static class Startup { public static List<StandInventory> InitPrefabs() { Logging<Plugin>.Info("Initializing Prefabs", 0); return Init(from p in ((IEnumerable<string>)Configs.StandPrefabNames.Value).Select((Func<string, GameObject>)ZNetScene.instance.GetPrefab) where (Object)(object)p != (Object)null select p); } public static List<StandInventory> Init(IEnumerable<GameObject> gameObjects) { //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_003e: Unknown result type (might be due to invalid IL or missing references) List<StandInventory> list = new List<StandInventory>(); bool flag = default(bool); foreach (GameObject gameObject in gameObjects) { InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(14, 1, ref flag); if (flag) { val.AppendLiteral("Initializing: "); val.AppendFormatted(((Object)gameObject).name); } Logging<Plugin>.Info(val, 0); if (!list.AddTo<ArmorStand>(gameObject) && !list.AddTo<ItemStand>(gameObject)) { Logging<Plugin>.Error((object)(((Object)gameObject).name + " is not ArmorStand or ItemStand"), (ushort)0); } } return list; } private static bool AddTo<T>(this List<StandInventory> standInventories, GameObject obj) where T : Component { T component = obj.GetComponent<T>(); if (!Object.op_Implicit((Object)(object)component)) { return false; } if (!(component is ArmorStand)) { if (!(component is ItemStand)) { throw new Exception($"Unknown component type: {((object)component).GetType()}"); } standInventories.Add(AddInv<ItemStandInventory>(obj)); } else { standInventories.Add(AddInv<ArmorStandInventory>(obj)); } return true; } private static T AddInv<T>(GameObject targetObject) where T : StandInventory { T val = targetObject.AddComponent<T>(); ((ZenMod<Plugin>)(object)ZenMod<Plugin>.Instance).HotLoad.Track((Object)(object)val); return val; } } internal static class StandInventoryExt { public static bool HasStandInventory(this MonoBehaviour comp, out StandInventory si) { return ((Component)comp).TryGetComponent<StandInventory>(ref si); } public static bool IsThisStandOpen(this MonoBehaviour comp) { return VirtualInventory.IsOpenedFrom(((Component)comp).gameObject); } } internal abstract class StandInventory : VirtualInventory { [HarmonyPatch] private static class Patch { [HarmonyPatch(typeof(InventoryGui), "OnStackAll")] private static class InventoryGuiOnStackAll { private static bool _isButtonPressed; [UsedImplicitly] private static void Prefix() { _isButtonPressed = true; } [UsedImplicitly] private static void Postfix() { _isButtonPressed = false; } [HarmonyPrefix] [HarmonyPatch(typeof(Inventory), "StackAll")] [HarmonyPriority(900)] private static void Inventory_StackAll(ref bool __runOriginal) { if (!VirtualInventory.IsOpened<StandInventory>()) { return; } __runOriginal = false; if (_isButtonPressed || (Opened is ArmorStandInventory && Configs.EnableArmorStandHoldToEquip.Value)) { if (Conflict.IsConflict) { Logging<Plugin>.Warning((object)"Conflicting mod detected, abort equipment swap to protect against item duplication.", 0); } else { Opened.SwapEquip(); } } } } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "Hide")] private static void InventoryGui_Hide(InventoryGui __instance) { if (VirtualInventory.IsOpened<StandInventory>() && Opened is ArmorStandInventory armorStandInventory) { armorStandInventory.ValidatePose(); } } } private Inventory? _inventory; private static readonly StringBuilder Sb = new StringBuilder(); private static StandInventory Opened { get { StandInventory result = default(StandInventory); if (!VirtualInventory.TryGetOpened<StandInventory>(ref result)) { throw new Exception("Can not access, not open"); } return result; } } protected override Inventory Inventory => _inventory ?? throw new NullReferenceException(); protected override string StackAllButtonLabel => "$inventory_use"; protected ZNetView Nview { get; private set; } public abstract void ShowErrorMessage(); protected abstract bool IsSameType(ItemData standItem, ItemData compareItem); protected abstract bool CanAttach(ItemData itemData, bool ignoreExisting); protected abstract bool CanSwap(ItemData externItem, out ItemData swapItem); public abstract void SwapEquip(); protected abstract void UpdateVisualFromContainer(); protected abstract bool CanHoldToEquip(); protected abstract bool IsStandInventoryDiff(); protected override bool IsWarded() { return true; } protected override bool IsStackAllButtonVisible() { if (IsAnyItemEquipable()) { return !Conflict.IsConflict; } return false; } protected override ZNetView GetZNetView() { return Nview; } protected void SetupInventory(string label, int width, int height) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (_inventory == null) { _inventory = new Inventory(label, (Sprite)null, width, height); Inventory? inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged)); } } public void SetLabel(string label) { if (_inventory != null) { _inventory.m_name = label; } } protected override void Awake() { if (!ZNetView.m_forceDisableInit) { Nview = ((Component)this).GetComponent<ZNetView>(); ((ZenMod<Plugin>)(object)ZenMod<Plugin>.Instance).HotLoad.Track((Object)(object)this); ((VirtualInventory)this).Awake(); } } protected override bool OnHoldToStack() { if (!CanHoldToEquip()) { return false; } SwapEquip(); return true; } public void Open() { if (((VirtualInventory)this).IsOpen || VirtualInventory.IsRecentlyClosed) { Logging<Plugin>.Info("Already open or recently closed, aborting", 0); } else { ((VirtualInventory)this).RequestOpen(); } } protected override void OnOpenAllow() { InventoryGridExt.ShowAmountText(InventoryGui.instance.ContainerGrid, false, -1); Logging<Plugin>.Info("Opened Stand", 0); } protected override void OnClose() { Timing.Delay((MonoBehaviour)(object)InventoryGui.instance, 0.5f, (Action)delegate { InventoryGridExt.ShowAmountText(InventoryGui.instance.ContainerGrid, true, -1); }); } private bool IsInUse() { return false; } private void OnInventoryChanged() { UpdateVisualFromContainer(); } private void OnDestroy() { ((ZenMod<Plugin>)(object)ZenMod<Plugin>.Instance).HotLoad.Untrack((Object)(object)this); } protected ItemData? GetItemDataFromZDO(string itemName, int index = -1) { //IL_001a: Expected O, but got Unknown try { return ZdoExt.GetItemData(Nview.GetZDO(), itemName, index); } catch (MissingItemException ex) { Logging<Plugin>.Warning((object)((Exception)ex).Message, 0); return null; } } public bool IsAnyItemEquipable() { return ((VirtualInventory)this).Inventory.GetAllItems().Any((ItemData item) => item.IsEquipable()); } public virtual string GetHoverName() { object obj = _inventory?.m_name; if (obj == null) { Piece val = default(Piece); if (!((Component)this).TryGetComponent<Piece>(ref val)) { return GameObjectExt.GetPrefabName(((Component)this).gameObject); } obj = val.m_name; } return (string)obj; } public virtual string GetHoverText() { Sb.Clear(); Sb.Append(GetHoverName()); if (!WardAccessExt.CanAccessWard((MonoBehaviour)(object)this, false)) { Sb.Append("\n$piece_noaccess"); } else if (CanHoldToEquip()) { Sb.Append("\n" + UI.PromptInteract + " $piece_use ($msg_hold_equip_hover)"); } else { Sb.Append("\n" + UI.PromptInteract + " $piece_use"); } return StringExt.Localize(Sb.ToString()); } public void EquipItemSwap(Player player, ItemData standItem) { //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_000d: 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_006e: Expected I4, but got Unknown ItemType itemType = standItem.m_shared.m_itemType; ItemData val = (ItemData)((itemType - 3) switch { 3 => ((Humanoid)player).m_helmetItem, 4 => ((Humanoid)player).m_chestItem, 8 => ((Humanoid)player).m_legItem, 14 => ((Humanoid)player).m_shoulderItem, 15 => ((Humanoid)player).m_utilityItem, 21 => ((Humanoid)player).m_trinketItem, 2 => ((Humanoid)player).m_leftItem ?? ((Humanoid)player).m_hiddenLeftItem, 1 => ((Humanoid)player).m_leftItem ?? ((Humanoid)player).m_hiddenLeftItem, 19 => ((Humanoid)player).m_leftItem ?? ((Humanoid)player).m_hiddenLeftItem, 0 => ((Humanoid)player).m_rightItem ?? ((Humanoid)player).m_hiddenRightItem, 11 => ((Humanoid)player).m_rightItem ?? ((Humanoid)player).m_hiddenRightItem, 16 => ((Humanoid)player).m_rightItem ?? ((Humanoid)player).m_hiddenRightItem, 17 => ((Humanoid)player).m_rightItem ?? ((Humanoid)player).m_hiddenRightItem, 12 => ((Humanoid)player).m_rightItem ?? ((Humanoid)player).m_hiddenRightItem, _ => throw new ArgumentOutOfRangeException(), }); Inventory inventory = ((Humanoid)player).GetInventory(); Inventory inventory2 = ((VirtualInventory)this).Inventory; if (val == null) { inventory.MoveItemToThis(inventory2, standItem); } else if (CanAttach(val, ignoreExisting: true) && IsSameType(standItem, val)) { InventoryExt.SwapItem(inventory, val, inventory2, standItem); } ((Humanoid)player).EquipItem(standItem, false); } public bool CanUseHotbarItem() { bool flag = IsInUse(); if (Configs.EnableHotbarUseItem.Value && !flag) { return true; } if (flag) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_inuse", 0, (Sprite)null); } return false; } protected override bool IsAddItemValid(ItemData item) { if (item.m_stack == 1) { return CanAttach(item, ignoreExisting: false); } return false; } protected override bool OnSelectedItemBefore(InventoryGui __instance, InventoryGrid grid, ItemData? item, Modifier mod, Vector2i pos) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_002e: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Invalid comparison between Unknown and I4 //IL_005d: 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) Player localPlayer = Player.m_localPlayer; Inventory inventory = __instance.m_containerGrid.GetInventory(); if (((Character)localPlayer).IsTeleporting()) { return true; } if ((int)mod != 2 && (int)mod != 0) { return true; } int dragAmount = __instance.m_dragAmount; if ((int)mod == 0) { Inventory inventory2 = grid.GetInventory(); Inventory dragInventory = __instance.m_dragInventory; ItemData dragItem = __instance.m_dragItem; if (dragItem == null) { return true; } if (inventory2 == dragInventory) { return true; } bool flag = false; ItemData itemAt = inventory2.GetItemAt(pos.x, pos.y); if (inventory2 == inventory) { __instance.m_dragAmount = 1; flag = ((itemAt == null || !Opened.IsSameType(itemAt, dragItem)) ? Opened.CanAttach(dragItem, ignoreExisting: false) : Opened.CanAttach(dragItem, ignoreExisting: true)); } if (inventory2 == ((Humanoid)localPlayer).GetInventory()) { if (itemAt != null) { if (ItemDataExt.GetPrefabName(dragItem) == ItemDataExt.GetPrefabName(itemAt) && ItemDataExt.IsStackable(dragItem)) { return true; } flag = Opened.CanAttach(itemAt, Opened.IsSameType(dragItem, itemAt)); } else { flag = true; } } if (flag) { if (itemAt == null) { return true; } InventoryExt.SwapItem(dragInventory, dragItem, inventory2, itemAt); __instance.SetupDragItem((ItemData)null, (Inventory)null, 0); return false; } } if ((int)mod == 2) { if ((Object)(object)grid == (Object)(object)__instance.ContainerGrid) { return true; } if (item != null && item.m_stack == 1) { if (Opened.CanAttach(item, ignoreExisting: false)) { return true; } if (Opened.CanSwap(item, out ItemData swapItem)) { InventoryExt.SwapItem(grid.GetInventory(), item, inventory, swapItem); return false; } } } __instance.m_dragAmount = dragAmount; Opened.ShowErrorMessage(); return false; } } internal class ItemStandInventory : StandInventory { private ItemStand _stand; private static readonly StringBuilder Sb = new StringBuilder(); protected override void Awake() { if (!((Component)this).TryGetComponent<ItemStand>(ref _stand)) { throw new Exception("ItemStand component not found on " + ((Object)this).name); } SetupInventory(_stand.m_name, 1, 1); base.Awake(); } public override void ShowErrorMessage() { ((Character)Player.m_localPlayer).Message((MessageType)2, "$piece_itemstand_cantattach", 0, (Sprite)null); } protected override bool IsSameType(ItemData standItem, ItemData compareItem) { if (compareItem.m_stack > 1) { return false; } if (_stand.CanAttach(standItem)) { return _stand.CanAttach(compareItem); } return false; } protected override bool CanAttach(ItemData itemData, bool ignoreExisting) { if (!ignoreExisting) { if (_stand.CanAttach(itemData)) { return ((VirtualInventory)this).Inventory.NrOfItems() == 0; } return false; } return _stand.CanAttach(itemData); } protected override bool CanSwap(ItemData externItem, out ItemData swapItem) { ItemData val = (swapItem = GetMountedItem()); if (val != null && IsSameType(val, externItem)) { return true; } return false; } public override void SwapEquip() { ItemData mountedItem = GetMountedItem(); if (mountedItem != null) { if (!mountedItem.IsEquipable()) { Logging<Plugin>.Info("Item stand item is not equipable, aborting swap.", 0); } else { EquipItemSwap(Player.m_localPlayer, mountedItem); } } } private ItemData? GetMountedItem() { if (((VirtualInventory)this).Inventory.NrOfItems() <= 0) { return GetAttachedItemFromZDO(); } return ((VirtualInventory)this).Inventory.GetItem(0); } private bool AttachItem(ItemData item) { //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_0051: Unknown result type (might be due to invalid IL or missing references) if (!_stand.CanAttach(item)) { return false; } if (!base.Nview.IsValid()) { return false; } base.Nview.ClaimOwnership(); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(16, 1, ref flag); if (flag) { val.AppendLiteral("Attaching item: "); val.AppendFormatted(ItemDataExt.GetPrefabName(item)); } Logging<Plugin>.Info(val, 0); ZDO zDO = base.Nview.GetZDO(); zDO.Set(ZDOVars.s_item, ItemDataExt.GetPrefabName(item)); ItemDrop.SaveToZDO(item, zDO); return true; } private ItemData? GetAttachedItemFromZDO() { return GetItemDataFromZDO(_stand.GetAttachedItem()); } protected override bool IsStandInventoryDiff() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (((VirtualInventory)this).Inventory.NrOfItems() == 0) { return _stand.HaveAttachment(); } if (!_stand.HaveAttachment()) { return true; } ItemData attachedItemFromZDO = GetAttachedItemFromZDO(); int num; if (attachedItemFromZDO == null) { num = 0; } else { num = ((!ItemDataExt.IsEqual(attachedItemFromZDO, ((VirtualInventory)this).Inventory.GetItem(0))) ? 1 : 0); if (num != 0) { goto IL_008a; } } bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(35, 1, ref flag); if (flag) { val.AppendLiteral("Container and stand are identical: "); val.AppendFormatted(((attachedItemFromZDO != null) ? ItemDataExt.GetName(attachedItemFromZDO) : null) ?? "No Item"); } Logging<Plugin>.Debug(val, 0); goto IL_008a; IL_008a: return (byte)num != 0; } protected override void LoadInventory() { //IL_0028: 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_004a: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info("Fill inventory from item stand", 0); ItemData attachedItemFromZDO = GetAttachedItemFromZDO(); if (attachedItemFromZDO != null) { ((VirtualInventory)this).Inventory.AddItem(attachedItemFromZDO); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(40, 1, ref flag); if (flag) { val.AppendLiteral("Added item to container from ItemStand: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemFromZDO)); } Logging<Plugin>.Info(val, 0); } } protected override void UpdateVisualFromContainer() { //IL_0047: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (!IsStandInventoryDiff()) { return; } Logging<Plugin>.Info("Updating visuals data", 0); ClearItemStand(); ItemData mountedItem = GetMountedItem(); if (mountedItem == null || AttachItem(mountedItem)) { UpdateVisualEveryone(); Transform transform = ((Component)this).transform; _stand.m_effects.Create(transform.position, transform.rotation, (Transform)null, 1f, -1); bool flag = default(bool); InterpolatedString<Plugin> val = new InterpolatedString<Plugin>(32, 2, ref flag); if (flag) { val.AppendFormatted("ItemStand"); val.AppendLiteral(" updated visual from container: "); val.AppendFormatted((mountedItem != null) ? ItemDataExt.GetPrefabName(mountedItem) : null); } Logging<Plugin>.Info(val, 0); } void ClearItemStand() { base.Nview.ClaimOwnership(); base.Nview.GetZDO().Set(ZDOVars.s_item, string.Empty); _stand.SetVisualItem(string.Empty, 0, 0, 0); } } private void UpdateVisualEveryone() { ZDO zDO = base.Nview.GetZDO(); string text = zDO.GetString(ZDOVars.s_item, ""); int num = zDO.GetInt(ZDOVars.s_variant, 0); int num2 = zDO.GetInt(ZDOVars.s_quality, 0); base.Nview.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { string.Empty, 0, 0, 0 }); base.Nview.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { text, num, num2, _stand.GetOrientation() }); } protected override bool IsStackAllButtonVisible() { if (Configs.EnableItemStandEquipButton.Value && !Conflict.IsConflict) { return base.IsStackAllButtonVisible(); } return false; } protected override bool CanHoldToEquip() { return false; } public override string GetHoverText() { Sb.Clear(); Sb.Append(base.GetHoverText()); if (WardAccessExt.CanAccessWard((MonoBehaviour)(object)this, false) && _stand.HasOrientations() && _stand.HaveAttachment()) { Sb.Append(StringExt.Localize("\n" + UI.PromptInteractAlt + " $hud_changeorientation")); } if (!Plugin.IsZenHoverItemInstalled && Configs.ShowItemOnStandName.Value) { ItemData? mountedItem = GetMountedItem(); string text = ((mountedItem != null) ? StringExt.Localize(ItemDataExt.GetName(mountedItem)) : null); if (!Utility.IsNullOrWhiteSpace(text)) { Sb.Append($"\n<color={UIColor.MinorInfo}>{text}</color>"); } } return Sb.ToString(); } } [HarmonyPatch] internal static class ItemStandPatch { [HarmonyPostfix] [HarmonyPatch(typeof(ItemStand), "GetHoverText")] private static void ItemStand_GetHoverText(ItemStand __instance, ref string __result) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory si)) { __result = si.GetHoverText(); } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemStand), "UseItem")] private static void ItemStand_UseItem(ItemStand __instance, ref bool __runOriginal, ref bool __result) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory si) && !si.CanUseHotbarItem()) { __runOriginal = false; __result = false; } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemStand), "Interact")] private static void ItemStand_Interact(ItemStand __instance, Humanoid user, bool alt, bool hold, ref bool __result, ref bool __runOriginal) { if (((MonoBehaviour)(object)__instance).HasStandInventory(out StandInventory si) && !alt) { __runOriginal = false; if (!hold) { __result = true; si.Open(); Game.instance.IncrementPlayerStat((PlayerStatType)24, 1f); } } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemStand), "SetVisualItem")] private static void ItemStand_SetVisualItem(ItemStand __instance, string itemName, int variant) { if (__instance.m_visualName != itemName || __instance.m_visualVariant != variant) { Object.Destroy((Object)(object)__instance.m_visualItem); } } [HarmonyPostfix] [HarmonyPatch(typeof(ItemStand), "RPC_DropItem")] private static void ItemStand_RPC_DropItem(ItemStand __instance) { if (((MonoBehaviour)(object)__instance).IsThisStandOpen()) { InventoryGui.instance.Hide(); } } } [Disable(new Type[] { typeof(StandInventory) })] [BepInPlugin("ZenDragon.ZenItemStands", "ZenItemStands", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod<Plugin> { public const string PluginName = "ZenItemStands"; public const string PluginVersion = "1.0.2"; public const string PluginGUID = "ZenDragon.ZenItemStands"; public static bool IsZenHoverItemInstalled => Chainloader.PluginInfos.ContainsKey("ZenDragon.ZenHoverItem"); protected override void Setup() { base.LanguageChanged += UpdateTranslations; base.HotLoad.PrefabInit += Startup.InitPrefabs; Conflict.Verify(); } protected override void TitleScene(bool isFirstBoot) { } protected override void WorldStart() { } protected override void Shutdown() { } protected override void HotRestore() { IEnumerable<GameObject> first = from stand in Object.FindObjectsByType<ItemStand>((FindObjectsSortMode)0) select ((Component)stand).gameObject; IEnumerable<GameObject> second = from stand in Object.FindObjectsByType<ArmorStand>((FindObjectsSortMode)0) select ((Component)stand).gameObject; Startup.Init(from obj in first.Concat(second) where ((IEnumerable<string>)Configs.StandPrefabNames.Value).Any((string prefabName) => prefabName == Utils.GetPrefabName(((Object)obj).name)) select obj); } private static void UpdateTranslations(string language) { if (Configs.EnableArmorStandAmericanSpelling.Value && language == "English") { Localization.instance.m_translations["piece_armorstand"] = "Armor Stand"; } } } } namespace ZenItemStands.Compatibility { internal static class Conflict { private static readonly string[] ConflictedMods = new string[3] { "aedenthorn.ExtendedPlayerInventory", "randyknapp.mods.equipmentandquickslots", "com.bruce.valheim.comfyquickslots" }; internal static bool IsConflict { get; private set; } internal static void Verify() { if (ConflictedMods.Any((string modID) => Chainloader.PluginInfos.ContainsKey(modID))) { IsConflict = true; Logging<Plugin>.Message((object)("ZenItemStands: The Use/Equip quick swap functionality will be disabled.\r\nThis is to protect against item duplication due to one of the following mods being installed:\r\n" + GeneralExtensions.Join<string>((IEnumerable<string>)ConflictedMods, (Func<string, string>)null, "\n")), 0); } } } }