From c5e35c9b6954e168e6bbfef040871448c8ef515a Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 12 Sep 2021 22:23:15 -0700 Subject: [PATCH] fix: Uses client bug to make addon containers work (#776) * Fixes tooltip for container furniture so it works. This doesn't work on ClassicUO. * Fixes double click opening container furniture by double clicking the addon component. * Fixes the context menu not showing up sometimes on the addon piece. Note: You cannot drop anything into the addon component since it might be far away and it is not a real container. There is no easy fix for this without building an entire custom container class for addons or changing how items drag/drop entirely. Requires closing/opening container gumps as it switches from one component to another that shares the same content. Also requires sharing tooltips, invalidated properties, process delta changes, etc. Not worth the effort. Screen_Shot_2021-09-12_at_4 27 28_PM --- Projects/Server/Items/Container.cs | 2 +- Projects/Server/Items/Item.cs | 50 +++++++++---------- Projects/UOContent/Gumps/AdminGump.cs | 44 ++++++++-------- .../UOContent/Items/Addons/AddonComponent.cs | 12 +++-- .../Items/Addons/AddonContainerComponent.cs | 26 ++++++++-- .../Items/Addons/ArcaneBookshelfEastAddon.cs | 16 +++--- .../Items/Addons/BaseAddonContainer.cs | 17 +++++++ .../UOContent/Items/Containers/Container.cs | 23 +-------- 8 files changed, 104 insertions(+), 86 deletions(-) diff --git a/Projects/Server/Items/Container.cs b/Projects/Server/Items/Container.cs index f0dd8e630..43a2ba939 100644 --- a/Projects/Server/Items/Container.cs +++ b/Projects/Server/Items/Container.cs @@ -763,7 +763,7 @@ namespace Server.Items { if (Core.ML) { - if (ParentsContain()) // Root Parent is the Mobile. Parent could be another containter. + if (ParentsContain()) // Root Parent is the Mobile. Parent could be another container. { list.Add( 1073841, // Contents: ~1_COUNT~/~2_MAXCOUNT~ items, ~3_WEIGHT~ stones diff --git a/Projects/Server/Items/Item.cs b/Projects/Server/Items/Item.cs index cfb7e14b8..7d507b93a 100644 --- a/Projects/Server/Items/Item.cs +++ b/Projects/Server/Items/Item.cs @@ -1332,39 +1332,36 @@ namespace Server if (openers != null) { - lock (openers) + for (var i = 0; i < openers.Count; ++i) { - for (var i = 0; i < openers.Count; ++i) + var mob = openers[i]; + + var range = GetUpdateRange(mob); + + if (mob.Map != map || !mob.InRange(worldLoc, range)) { - var mob = openers[i]; - - var range = GetUpdateRange(mob); - - if (mob.Map != map || !mob.InRange(worldLoc, range)) + openers.RemoveAt(i--); + } + else + { + if (mob == rootParent || mob == tradeRecip) { - openers.RemoveAt(i--); + continue; } - else + + var ns = mob.NetState; + + if (ns != null && mob.CanSee(this)) { - if (mob == rootParent || mob == tradeRecip) - { - continue; - } - - var ns = mob.NetState; - - if (ns != null && mob.CanSee(this)) - { - ns.SendContainerContentUpdate(this); - SendOPLPacketTo(ns); - } + ns.SendContainerContentUpdate(this); + SendOPLPacketTo(ns); } } + } - if (openers.Count == 0) - { - contParent.Openers = null; - } + if (openers.Count == 0) + { + contParent.Openers = null; } } @@ -1719,6 +1716,7 @@ namespace Server } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool GetFlag(ImplFlag flag) => (m_Flags & flag) != 0; public BounceInfo GetBounce() => LookupCompactInfo()?.m_Bounce; @@ -2408,7 +2406,7 @@ namespace Server } #nullable enable - public void InvalidateProperties() + public virtual void InvalidateProperties() { if (!ObjectPropertyList.Enabled) { diff --git a/Projects/UOContent/Gumps/AdminGump.cs b/Projects/UOContent/Gumps/AdminGump.cs index add8aa9ec..25777e491 100644 --- a/Projects/UOContent/Gumps/AdminGump.cs +++ b/Projects/UOContent/Gumps/AdminGump.cs @@ -2696,9 +2696,9 @@ namespace Server.Gumps { case 0: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_Information, 0, null, @@ -2710,9 +2710,9 @@ namespace Server.Gumps } case 1: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_Characters, 0, null, @@ -2724,9 +2724,9 @@ namespace Server.Gumps } case 2: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_Comments, 0, null, @@ -2738,23 +2738,23 @@ namespace Server.Gumps } case 3: { - @from.SendGump( - new AdminGump(@from, AdminGumpPage.AccountDetails_Tags, 0, null, null, m_State) + from.SendGump( + new AdminGump(from, AdminGumpPage.AccountDetails_Tags, 0, null, null, m_State) ); break; } case 13: { - @from.SendGump( - new AdminGump(@from, AdminGumpPage.AccountDetails_Access, 0, null, null, m_State) + from.SendGump( + new AdminGump(from, AdminGumpPage.AccountDetails_Access, 0, null, null, m_State) ); break; } case 14: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, @@ -2766,9 +2766,9 @@ namespace Server.Gumps } case 15: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_Access_Restrictions, 0, null, @@ -2780,14 +2780,14 @@ namespace Server.Gumps } case 4: { - @from.Prompt = new AddCommentPrompt(m_State as Account); - @from.SendMessage("Enter the new account comment."); + from.Prompt = new AddCommentPrompt(m_State as Account); + from.SendMessage("Enter the new account comment."); break; } case 5: { - @from.Prompt = new AddTagNamePrompt(m_State as Account); - @from.SendMessage("Enter the new tag name."); + from.Prompt = new AddTagNamePrompt(m_State as Account); + from.SendMessage("Enter the new tag name."); break; } case 6: @@ -2897,9 +2897,9 @@ namespace Server.Gumps } case 8: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_ChangePassword, 0, null, @@ -2911,9 +2911,9 @@ namespace Server.Gumps } case 9: { - @from.SendGump( + from.SendGump( new AdminGump( - @from, + from, AdminGumpPage.AccountDetails_ChangeAccess, 0, null, diff --git a/Projects/UOContent/Items/Addons/AddonComponent.cs b/Projects/UOContent/Items/Addons/AddonComponent.cs index e7b58f8d6..6e3d64908 100644 --- a/Projects/UOContent/Items/Addons/AddonComponent.cs +++ b/Projects/UOContent/Items/Addons/AddonComponent.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using Server.ContextMenus; using Server.Engines.Craft; namespace Server.Items @@ -141,10 +143,7 @@ namespace Server.Items } } - public override void OnDoubleClick(Mobile from) - { - _addon?.OnComponentUsed(this, from); - } + public override void OnDoubleClick(Mobile from) => _addon?.OnComponentUsed(this, from); public override void OnLocationChange(Point3D old) { @@ -162,6 +161,11 @@ namespace Server.Items } } + public override void GetProperties(ObjectPropertyList list) => _addon?.GetProperties(list); + + public override void GetContextMenuEntries(Mobile from, List list) => + _addon?.GetContextMenuEntries(from, list); + public override void OnAfterDelete() { base.OnAfterDelete(); diff --git a/Projects/UOContent/Items/Addons/AddonContainerComponent.cs b/Projects/UOContent/Items/Addons/AddonContainerComponent.cs index 7baf0bb64..509d430ea 100644 --- a/Projects/UOContent/Items/Addons/AddonContainerComponent.cs +++ b/Projects/UOContent/Items/Addons/AddonContainerComponent.cs @@ -1,5 +1,8 @@ +using System; +using System.Buffers.Binary; using System.Collections.Generic; using Server.ContextMenus; +using Server.Network; namespace Server.Items { @@ -19,11 +22,11 @@ namespace Server.Items [SerializableField(0)] [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] - public BaseAddonContainer _addon; + private BaseAddonContainer _addon; [SerializableField(1)] [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] - public Point3D _offset; + private Point3D _offset; [Hue] [CommandProperty(AccessLevel.GameMaster)] @@ -65,9 +68,6 @@ namespace Server.Items } } - public override void GetContextMenuEntries(Mobile from, List list) => - _addon?.GetContextMenuEntries(from, list); - public override void OnMapChange() { if (_addon != null) @@ -76,6 +76,11 @@ namespace Server.Items } } + public override void GetProperties(ObjectPropertyList list) => _addon?.GetProperties(list); + + public override void GetContextMenuEntries(Mobile from, List list) => + _addon?.GetContextMenuEntries(from, list); + public override void OnAfterDelete() { base.OnAfterDelete(); @@ -83,6 +88,17 @@ namespace Server.Items _addon?.Delete(); } + public override void SendWorldPacketTo(NetState ns, ReadOnlySpan world = default) + { + Span buffer = stackalloc byte[OutgoingEntityPackets.MaxWorldEntityPacketLength].InitializePacket(); + var length = OutgoingItemPackets.CreateWorldItem(buffer, this); + // Use an itemid of a real container + BinaryPrimitives.WriteUInt16BigEndian(buffer[7..9], (ushort)(_addon?.ItemID ?? 0x9AB)); + ns.Send(buffer[..length]); + + base.SendWorldPacketTo(ns, world); + } + [AfterDeserialization] private void AfterDeserialization() { diff --git a/Projects/UOContent/Items/Addons/ArcaneBookshelfEastAddon.cs b/Projects/UOContent/Items/Addons/ArcaneBookshelfEastAddon.cs index 02e1c448b..ba197ed84 100644 --- a/Projects/UOContent/Items/Addons/ArcaneBookshelfEastAddon.cs +++ b/Projects/UOContent/Items/Addons/ArcaneBookshelfEastAddon.cs @@ -1,27 +1,29 @@ namespace Server.Items { [Serializable(0)] - public partial class ArcaneBookshelfEastAddon : BaseAddon + public partial class ArcaneBookshelfEastAddon : BaseAddonContainer { [Constructible] - public ArcaneBookshelfEastAddon() + public ArcaneBookshelfEastAddon() : base(0x3084) { - AddComponent(new AddonComponent(0x3084), 0, 0, 0); - AddComponent(new AddonComponent(0x3085), -1, 0, 0); + AddComponent(new AddonContainerComponent(0x3085), -1, 0, 0); } - public override BaseAddonDeed Deed => new ArcaneBookshelfEastDeed(); + public override BaseAddonContainerDeed Deed => new ArcaneBookshelfEastDeed(); + public override bool RetainDeedHue => true; + public override int DefaultGumpID => 0x107; + public override int DefaultDropSound => 0x42; } [Serializable(0)] - public partial class ArcaneBookshelfEastDeed : BaseAddonDeed + public partial class ArcaneBookshelfEastDeed : BaseAddonContainerDeed { [Constructible] public ArcaneBookshelfEastDeed() { } - public override BaseAddon Addon => new ArcaneBookshelfEastAddon(); + public override BaseAddonContainer Addon => new ArcaneBookshelfEastAddon(); public override int LabelNumber => 1073371; // arcane bookshelf (east) } } diff --git a/Projects/UOContent/Items/Addons/BaseAddonContainer.cs b/Projects/UOContent/Items/Addons/BaseAddonContainer.cs index c812ac3c5..cc94b8265 100644 --- a/Projects/UOContent/Items/Addons/BaseAddonContainer.cs +++ b/Projects/UOContent/Items/Addons/BaseAddonContainer.cs @@ -187,6 +187,19 @@ namespace Server.Items } } + public override void InvalidateProperties() + { + base.InvalidateProperties(); + + if (_components != null) + { + foreach (var component in _components) + { + component.InvalidateProperties(); + } + } + } + // Handles v0 with old Enum -> Int casting private void Deserialize(IGenericReader reader, int version) { @@ -332,6 +345,10 @@ namespace Server.Items public virtual void OnComponentUsed(AddonContainerComponent c, Mobile from) { + if (!Deleted) + { + OnDoubleClick(from); + } } } } diff --git a/Projects/UOContent/Items/Containers/Container.cs b/Projects/UOContent/Items/Containers/Container.cs index d2d57ef38..872bc6d77 100644 --- a/Projects/UOContent/Items/Containers/Container.cs +++ b/Projects/UOContent/Items/Containers/Container.cs @@ -16,28 +16,9 @@ namespace Server.Items { } - public override int DefaultMaxWeight - { - get - { - if (IsSecure) - { - return 0; - } + public override int DefaultMaxWeight => IsSecure ? 0 : base.DefaultMaxWeight; - return base.DefaultMaxWeight; - } - } - - public override bool IsAccessibleTo(Mobile m) - { - if (!BaseHouse.CheckAccessible(m, this)) - { - return false; - } - - return base.IsAccessibleTo(m); - } + public override bool IsAccessibleTo(Mobile m) => BaseHouse.CheckAccessible(m, this) && base.IsAccessibleTo(m); public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) {