From 0b4ee8b5b5589b8319fa1d699228a75aee0b5ace Mon Sep 17 00:00:00 2001 From: sven-n Date: Tue, 22 Oct 2024 21:29:32 +0200 Subject: [PATCH 1/4] Fixed ancient options in extended item serializer --- src/GameServer/RemoteView/ItemSerializerExtended.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GameServer/RemoteView/ItemSerializerExtended.cs b/src/GameServer/RemoteView/ItemSerializerExtended.cs index 2eb476e84..2b6072bbc 100644 --- a/src/GameServer/RemoteView/ItemSerializerExtended.cs +++ b/src/GameServer/RemoteView/ItemSerializerExtended.cs @@ -452,7 +452,7 @@ public int Length } } - private int ExcellentIndex => this.Options.HasFlag(OptionFlags.HasOption) ? 6 : 5; + private int ExcellentIndex => this.Options.HasFlag(OptionFlags.HasExcellent) ? 6 : 5; private int AncientIndex => this.Options.HasFlag(OptionFlags.HasAncient) ? this.ExcellentIndex + 1 : this.ExcellentIndex; From 57f11f13203639413638874819e7d59360c8518d Mon Sep 17 00:00:00 2001 From: Benito Go III Date: Wed, 23 Oct 2024 20:19:23 +0800 Subject: [PATCH 2/4] Fixed excellent options in extended item serializer --- src/GameServer/RemoteView/ItemSerializerExtended.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/GameServer/RemoteView/ItemSerializerExtended.cs b/src/GameServer/RemoteView/ItemSerializerExtended.cs index 2b6072bbc..bc296920d 100644 --- a/src/GameServer/RemoteView/ItemSerializerExtended.cs +++ b/src/GameServer/RemoteView/ItemSerializerExtended.cs @@ -452,7 +452,9 @@ public int Length } } - private int ExcellentIndex => this.Options.HasFlag(OptionFlags.HasExcellent) ? 6 : 5; + private int AdditionalOptionIndex => this.Options.HasFlag(OptionFlags.HasOption) ? 5 : 4; + + private int ExcellentIndex => this.Options.HasFlag(OptionFlags.HasExcellent) ? this.AdditionalOptionIndex + 1 : this.AdditionalOptionIndex; private int AncientIndex => this.Options.HasFlag(OptionFlags.HasAncient) ? this.ExcellentIndex + 1 : this.ExcellentIndex; From 6c2fb92f8a0a659ed7ea1f650520835b8eaf9ad4 Mon Sep 17 00:00:00 2001 From: Benito Go III Date: Thu, 24 Oct 2024 04:35:37 +0800 Subject: [PATCH 3/4] Fixed ItemGroup value of AppearanceChange packet on equip/unequip of item/pet --- src/GameLogic/InventoryStorage.cs | 11 ++++++----- src/GameLogic/ItemEventArgs.cs | 15 +++++++++++---- .../Views/World/IAppearanceChangedPlugIn.cs | 7 ++++--- .../RemoteView/World/AppearanceChangedPlugIn.cs | 6 +++--- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/GameLogic/InventoryStorage.cs b/src/GameLogic/InventoryStorage.cs index 12fb47c2d..69a482fa5 100644 --- a/src/GameLogic/InventoryStorage.cs +++ b/src/GameLogic/InventoryStorage.cs @@ -31,7 +31,7 @@ public InventoryStorage(Player player, IGameContext context) new ItemStorageAdapter(player.SelectedCharacter?.Inventory ?? throw Error.NotInitializedProperty(player, "SelectedCharacter.Inventory"), FirstEquippableItemSlotIndex, player.GetInventorySize())) { this._player = player; - this.EquippedItemsChanged += async eventArgs => await this.UpdateItemsOnChangeAsync(eventArgs.Item).ConfigureAwait(false); + this.EquippedItemsChanged += async eventArgs => await this.UpdateItemsOnChangeAsync(eventArgs.Item, eventArgs.IsEquipped).ConfigureAwait(false); this._gameContext = context; if (player.SelectedCharacter.InventoryExtensions > 0) @@ -110,7 +110,7 @@ public override async ValueTask AddItemAsync(byte slot, Item item) var isEquippedItem = this.IsWearingSlot(slot); if (isEquippedItem && this.EquippedItemsChanged is { } eventHandler) { - await eventHandler(new ItemEventArgs(convertedItem ?? item)).ConfigureAwait(false); + await eventHandler(new ItemEventArgs(convertedItem ?? item, true)).ConfigureAwait(false); } } @@ -124,7 +124,7 @@ public override async ValueTask RemoveItemAsync(Item item) await base.RemoveItemAsync(item).ConfigureAwait(false); if (isEquippedItem && this.EquippedItemsChanged is { } eventHandler) { - await eventHandler(new ItemEventArgs(item)).ConfigureAwait(false); + await eventHandler(new ItemEventArgs(item, false)).ConfigureAwait(false); } } @@ -133,11 +133,12 @@ private bool IsWearingSlot(int slot) return slot >= FirstEquippableItemSlotIndex && slot <= LastEquippableItemSlotIndex; } - private async ValueTask UpdateItemsOnChangeAsync(Item item) + private async ValueTask UpdateItemsOnChangeAsync(Item item, bool isEquipped) { this._player.OnAppearanceChanged(); + await this._player.ForEachWorldObserverAsync( - p => p.AppearanceChangedAsync(this._player, item), + p => p.AppearanceChangedAsync(this._player, item, isEquipped), false).ConfigureAwait(false); // in my tests it was not needed to send the appearance to the own players client. if (this._player.Attributes is null) diff --git a/src/GameLogic/ItemEventArgs.cs b/src/GameLogic/ItemEventArgs.cs index 71a256f15..2db5c2e60 100644 --- a/src/GameLogic/ItemEventArgs.cs +++ b/src/GameLogic/ItemEventArgs.cs @@ -9,18 +9,25 @@ namespace MUnique.OpenMU.GameLogic; /// /// public class ItemEventArgs : EventArgs -{ +{ /// /// Initializes a new instance of the class. /// - /// The item. - public ItemEventArgs(Item item) + /// The item. + /// Whether equipped or not + public ItemEventArgs(Item item, bool isEquipped) { this.Item = item; + this.IsEquipped = isEquipped; } /// /// Gets the item which is involved at the event. /// - public Item Item { get; } + public Item Item { get; } + + /// + /// Gets a value indicating whether the item is equipped at the event. + /// + public bool IsEquipped { get; } } \ No newline at end of file diff --git a/src/GameLogic/Views/World/IAppearanceChangedPlugIn.cs b/src/GameLogic/Views/World/IAppearanceChangedPlugIn.cs index 075ac5026..dbe2cbaef 100644 --- a/src/GameLogic/Views/World/IAppearanceChangedPlugIn.cs +++ b/src/GameLogic/Views/World/IAppearanceChangedPlugIn.cs @@ -8,11 +8,12 @@ namespace MUnique.OpenMU.GameLogic.Views.World; /// Interface of a view whose implementation informs about the changed appearance of a player. /// public interface IAppearanceChangedPlugIn : IViewPlugIn -{ +{ /// /// The appearance of a player changed. /// /// The changed player. - /// The changed item. - ValueTask AppearanceChangedAsync(Player changedPlayer, Item changedItem); + /// The changed item. + /// + ValueTask AppearanceChangedAsync(Player changedPlayer, Item changedItem, bool isEquipped); } \ No newline at end of file diff --git a/src/GameServer/RemoteView/World/AppearanceChangedPlugIn.cs b/src/GameServer/RemoteView/World/AppearanceChangedPlugIn.cs index 56213edb7..278aadf91 100644 --- a/src/GameServer/RemoteView/World/AppearanceChangedPlugIn.cs +++ b/src/GameServer/RemoteView/World/AppearanceChangedPlugIn.cs @@ -30,7 +30,7 @@ public class AppearanceChangedPlugIn : IAppearanceChangedPlugIn public AppearanceChangedPlugIn(RemotePlayer player) => this._player = player; /// - public async ValueTask AppearanceChangedAsync(Player changedPlayer, Item item) + public async ValueTask AppearanceChangedAsync(Player changedPlayer, Item item, bool isEquipped) { var connection = this._player.Connection; if (connection is null || changedPlayer.Inventory is not { } inventory) @@ -94,7 +94,7 @@ public class AppearanceChangedExtendedPlugIn : IAppearanceChangedPlugIn public AppearanceChangedExtendedPlugIn(RemotePlayer player) => this._player = player; /// - public async ValueTask AppearanceChangedAsync(Player changedPlayer, Item item) + public async ValueTask AppearanceChangedAsync(Player changedPlayer, Item item, bool isEquipped) { var connection = this._player.Connection; if (connection is null || changedPlayer.Inventory is null) @@ -105,7 +105,7 @@ public async ValueTask AppearanceChangedAsync(Player changedPlayer, Item item) await connection.SendAppearanceChangedExtendedAsync( changedPlayer.GetId(this._player), item.ItemSlot, - (byte)(item.Definition?.Group ?? 0xFF), + (byte)((isEquipped? item.Definition?.Group : 0xFF) ?? 0xFF), (ushort)(item.Definition?.Number ?? 0xFFFF), item.Level, (byte)(ItemSerializerHelper.GetExcellentByte(item) | ItemSerializerHelper.GetFenrirByte(item)), From a639b31ed698905f71bc1a08a74357923d2b39dd Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 24 Oct 2024 18:46:01 +0200 Subject: [PATCH 4/4] Fixed serialization of ancient item appearance --- src/GameLogic/CharacterExtensions.cs | 14 +++++++++++--- src/GameLogic/ItemExtensions.cs | 9 ++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/GameLogic/CharacterExtensions.cs b/src/GameLogic/CharacterExtensions.cs index d4fe91500..8eb5706ea 100644 --- a/src/GameLogic/CharacterExtensions.cs +++ b/src/GameLogic/CharacterExtensions.cs @@ -52,9 +52,17 @@ public static bool HasFullAncientSetEquipped(this Character character) i.ItemSlot <= InventoryConstants.LastEquippableItemSlotIndex && i.ItemSlot >= InventoryConstants.FirstEquippableItemSlotIndex && i.ItemSetGroups.Any(group => group.AncientSetDiscriminator > 0)) - .Select(i => new { Item = i.Definition, Set = i.ItemSetGroups.First(s => s.AncientSetDiscriminator > 0) }); - var ancientSets = equippedAncientSetItems.Select(i => i.Set).Distinct(); - return ancientSets.Any(set => set.ItemSetGroup?.Items.All(setItem => equippedAncientSetItems.Any(i => i.Item == setItem.ItemDefinition && i.Set == set)) ?? false); + .Select(i => + new + { + Item = i.Definition, + Set = i.ItemSetGroups.First(s => s.AncientSetDiscriminator > 0), + }); + var ancientSets = equippedAncientSetItems.Select(i => i.Set.ItemSetGroup).WhereNotNull().Distinct(); + return ancientSets.Any(set => + set.Items.All(setItem => equippedAncientSetItems.Any(i => + object.Equals(i.Item, setItem.ItemDefinition) + && object.Equals(i.Set.ItemSetGroup, set)))); } /// diff --git a/src/GameLogic/ItemExtensions.cs b/src/GameLogic/ItemExtensions.cs index 6a6f63441..5a92fc5c2 100644 --- a/src/GameLogic/ItemExtensions.cs +++ b/src/GameLogic/ItemExtensions.cs @@ -87,7 +87,7 @@ public static byte GetMaximumDurabilityOfOnePiece(this Item item) /// public static bool IsAncient(this Item item) { - return item.ItemOptions.Any(link => link.ItemOption?.OptionType == ItemOptionTypes.AncientBonus); + return item.ItemSetGroups.Any(itemSet => itemSet.AncientSetDiscriminator > 0); } /// @@ -305,6 +305,13 @@ public static ItemAppearance GetAppearance(this Item item) .Select(option => option.ItemOption!.OptionType!) .Distinct() .ForEach(appearance.VisibleOptions.Add); + if (item.IsAncient()) + { + // 1. The ancient option is not included in the item.ItemOptions. + // 2. The bonus option is not always existing for ancient items. And it's not marked as visible. + // -> we check it based on the item set group. + appearance.VisibleOptions.Add(ItemOptionTypes.AncientOption); + } return appearance; }