using 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(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().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)_stand.m_slots).FirstOrDefault((Func)((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 val = new InterpolatedString(14, 2, ref flag); if (flag) { val.AppendLiteral("Index: "); val.AppendFormatted(index); val.AppendLiteral(" Item: "); val.AppendFormatted(attachedItem); } Logging.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 val = new InterpolatedString(11, 1, ref flag); if (flag) { val.AppendLiteral("Diff Item: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemData)); } Logging.Info(val, 0); return true; } num++; } bool num2 = num != ((VirtualInventory)this).Inventory.NrOfItems(); if (!num2) { InterpolatedString val = new InterpolatedString(41, 1, ref flag); if (flag) { val.AppendLiteral("Container and stand are identical: "); val.AppendFormatted(num); val.AppendLiteral(" items"); } Logging.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 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.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 val = new InterpolatedString(29, 2, ref flag); if (flag) { val.AppendFormatted("ArmorStand"); val.AppendLiteral(" loaded "); val.AppendFormatted(num); val.AppendLiteral(" items from container"); } Logging.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.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 val = new InterpolatedString(46, 1, ref flag); if (flag) { val.AppendLiteral("Added item to container from ArmorStand slot: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemData)); } Logging.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(); 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 val = new InterpolatedString(8, 2, ref flag); if (flag) { val.AppendFormatted("SetPose"); val.AppendLiteral(" index: "); val.AppendFormatted(__instance.m_pose); } Logging.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(); 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.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(); 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 StandPrefabNames; public static readonly ConfigEntry EnableHotbarUseItem; private const string SECTION_ARMORSTAND = "Piece: ArmorStand"; public static readonly ConfigEntry EnableArmorStandPoseChange; public static readonly ConfigEntry EnableArmorStandHoldToEquip; public static readonly ConfigEntry EnableArmorStandEquipButton; public static readonly ConfigEntry EnableArmorStandAmericanSpelling; private const string SECTION_ITEMSTAND = "Piece: ItemStand"; public static readonly ConfigEntry EnableItemStandEquipButton; public static readonly ConfigEntry 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)val).Add("itemstand"); ((List)val).Add("itemstandh"); ((List)val).Add("ArmorStand"); ((List)val).Add("Placeable_HardRock"); StandPrefabNames = Config.Define(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(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(true, "Piece: ArmorStand", "Enable Pose Changing", false, "Enable changing poses of armor stands. NOTE: Stand must have chest and legs armor."); EnableArmorStandHoldToEquip = Config.Define(true, "Piece: ArmorStand", "Enable Hold To Equip", false, "Should (Hold to equip) be available on Armor Stands hover text?"); EnableArmorStandEquipButton = Config.Define(true, "Piece: ArmorStand", "Enable Use/Equip Button", true, "Enable the use/equip button on armor stands to quickly swap equipped gear."); EnableArmorStandAmericanSpelling = Config.Define(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(true, "Piece: ItemStand", "Enable Use/Equip Button", true, "Enable the use/equip button on item stands to quickly swap equipped gear."); ShowItemOnStandName = Config.Define(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 InitPrefabs() { Logging.Info("Initializing Prefabs", 0); return Init(from p in ((IEnumerable)Configs.StandPrefabNames.Value).Select((Func)ZNetScene.instance.GetPrefab) where (Object)(object)p != (Object)null select p); } public static List Init(IEnumerable 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 list = new List(); bool flag = default(bool); foreach (GameObject gameObject in gameObjects) { InterpolatedString val = new InterpolatedString(14, 1, ref flag); if (flag) { val.AppendLiteral("Initializing: "); val.AppendFormatted(((Object)gameObject).name); } Logging.Info(val, 0); if (!list.AddTo(gameObject) && !list.AddTo(gameObject)) { Logging.Error((object)(((Object)gameObject).name + " is not ArmorStand or ItemStand"), (ushort)0); } } return list; } private static bool AddTo(this List standInventories, GameObject obj) where T : Component { T component = obj.GetComponent(); 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(obj)); } else { standInventories.Add(AddInv(obj)); } return true; } private static T AddInv(GameObject targetObject) where T : StandInventory { T val = targetObject.AddComponent(); ((ZenMod)(object)ZenMod.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(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()) { return; } __runOriginal = false; if (_isButtonPressed || (Opened is ArmorStandInventory && Configs.EnableArmorStandHoldToEquip.Value)) { if (Conflict.IsConflict) { Logging.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() && 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(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(); ((ZenMod)(object)ZenMod.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.Info("Already open or recently closed, aborting", 0); } else { ((VirtualInventory)this).RequestOpen(); } } protected override void OnOpenAllow() { InventoryGridExt.ShowAmountText(InventoryGui.instance.ContainerGrid, false, -1); Logging.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)(object)ZenMod.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.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(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(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.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 val = new InterpolatedString(16, 1, ref flag); if (flag) { val.AppendLiteral("Attaching item: "); val.AppendFormatted(ItemDataExt.GetPrefabName(item)); } Logging.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 val = new InterpolatedString(35, 1, ref flag); if (flag) { val.AppendLiteral("Container and stand are identical: "); val.AppendFormatted(((attachedItemFromZDO != null) ? ItemDataExt.GetName(attachedItemFromZDO) : null) ?? "No Item"); } Logging.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.Info("Fill inventory from item stand", 0); ItemData attachedItemFromZDO = GetAttachedItemFromZDO(); if (attachedItemFromZDO != null) { ((VirtualInventory)this).Inventory.AddItem(attachedItemFromZDO); bool flag = default(bool); InterpolatedString val = new InterpolatedString(40, 1, ref flag); if (flag) { val.AppendLiteral("Added item to container from ItemStand: "); val.AppendFormatted(ItemDataExt.GetName(attachedItemFromZDO)); } Logging.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.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 val = new InterpolatedString(32, 2, ref flag); if (flag) { val.AppendFormatted("ItemStand"); val.AppendLiteral(" updated visual from container: "); val.AppendFormatted((mountedItem != null) ? ItemDataExt.GetPrefabName(mountedItem) : null); } Logging.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{text}"); } } 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 { 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 first = from stand in Object.FindObjectsByType((FindObjectsSortMode)0) select ((Component)stand).gameObject; IEnumerable second = from stand in Object.FindObjectsByType((FindObjectsSortMode)0) select ((Component)stand).gameObject; Startup.Init(from obj in first.Concat(second) where ((IEnumerable)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.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((IEnumerable)ConflictedMods, (Func)null, "\n")), 0); } } } }