From 397ea7be4b4337205434842a4da71f411e28fc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82ngelo=20Tadeucci?= Date: Tue, 22 Apr 2025 19:31:36 -0300 Subject: [PATCH 1/3] Fix UGC Templates stacking --- Maple2.Server.Game/Manager/HousingManager.cs | 2 +- .../Manager/Items/FurnishingManager.cs | 48 +++++++++++++----- .../Manager/Items/InventoryManager.cs | 2 +- .../Manager/Items/ItemManager.cs | 49 ------------------- 4 files changed, 38 insertions(+), 63 deletions(-) diff --git a/Maple2.Server.Game/Manager/HousingManager.cs b/Maple2.Server.Game/Manager/HousingManager.cs index 002f95053..6655d2f99 100644 --- a/Maple2.Server.Game/Manager/HousingManager.cs +++ b/Maple2.Server.Game/Manager/HousingManager.cs @@ -541,7 +541,7 @@ public bool TryPlaceCube(HeldCube cube, Plot plot, ItemMetadata itemMetadata, in } if (!session.Item.Furnishing.TryPlaceCube(cube.Id, out result)) { - long itemUid = session.Item.Furnishing.AddCube(cube.ItemId); + long itemUid = session.Item.Furnishing.AddCube(cube); if (itemUid == 0) { session.Send(CubePacket.Error(UgcMapError.s_ugcmap_not_for_sale)); return false; diff --git a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs index 90ed79e9a..56636c8a8 100644 --- a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs +++ b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs @@ -152,6 +152,23 @@ public bool PurchaseCube(FurnishingShopTable.Entry furnishingShopMetadata) { return true; } + public long AddCube(HeldCube cube) { + const int amount = 1; + lock (session.Item) { + int count = storage.Count; + long itemUid = AddStorage(cube); + if (itemUid == 0) { + return 0; + } + + session.Send(FurnishingStoragePacket.Purchase(cube.ItemId, amount)); + if (storage.Count != count) { + session.Send(FurnishingStoragePacket.Count(storage.Count)); + } + return itemUid; + } + } + // TODO: NOTE - This should also be called for opening a furnishing box public long AddCube(int id) { const int amount = 1; @@ -193,7 +210,7 @@ public bool RetrieveCube(long uid) { return false; } - long itemUid = AddStorage(cube.ItemId); + long itemUid = AddStorage(cube); if (itemUid == 0) { logger.Fatal("Failed to return cube: {CubeId} to storage", cube.Id); throw new InvalidOperationException($"Failed to return cube: {cube.Id} to storage"); @@ -203,6 +220,15 @@ public bool RetrieveCube(long uid) { } } + private long AddStorage(HeldCube cube) { + Item? item = session.Field.ItemDrop.CreateItem(cube.ItemId); + if (item == null) { + return 0; + } + + return AddStorage(item, cube.Template); + } + private long AddStorage(int itemId) { Item? item = session.Field.ItemDrop.CreateItem(itemId); if (item == null) { @@ -212,28 +238,26 @@ private long AddStorage(int itemId) { return AddStorage(item); } - public long AddStorage(Item? item) { + public long AddStorage(Item item, UgcItemLook? template = null) { const int amount = 1; - if (item == null) { - return 0; - } + lock (session.Item) { - Item? stored = storage.FirstOrDefault(existing => existing.Id == item.Id); + Item? stored = storage.FirstOrDefault(existing => existing.Id == item.Id && existing.Template?.Url == template?.Url); if (stored == null) { item.Group = ItemGroup.Furnishing; using GameStorage.Request db = session.GameStorage.Context(); - item = db.CreateItem(session.AccountId, item); - if (item == null) { + Item? newItem = db.CreateItem(session.AccountId, item); + if (newItem == null) { return 0; } - if (storage.Add(item).Count <= 0) { - db.SaveItems(0, item); + if (storage.Add(newItem).Count <= 0) { + db.SaveItems(0, newItem); return 0; } - session.Send(FurnishingStoragePacket.Add(item)); - return item.Uid; + session.Send(FurnishingStoragePacket.Add(newItem)); + return newItem.Uid; } if (stored.Amount + amount > item.Metadata.Property.SlotMax) { diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index 656d427a7..69886eafd 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -161,7 +161,7 @@ public bool Add(Item add, bool notifyNew = false, bool commit = false) { } if (add.Type.IsFurnishing) { - session.Item.Furnishing.AddStorage(add); + session.Item.Furnishing.AddStorage(add, add.Template); session.Item.Inventory.Discard(add); return true; } diff --git a/Maple2.Server.Game/Manager/Items/ItemManager.cs b/Maple2.Server.Game/Manager/Items/ItemManager.cs index 6fab75d03..cbd395de7 100644 --- a/Maple2.Server.Game/Manager/Items/ItemManager.cs +++ b/Maple2.Server.Game/Manager/Items/ItemManager.cs @@ -46,55 +46,6 @@ public ItemManager(GameStorage.Request db, GameSession session, ItemStatsCalcula return item ?? Equips.Outfit.Values.FirstOrDefault(outfit => outfit.Uid == uid); } - [Obsolete("Use in actor.ItemDrop instead")] - public Item? CreateItem(int itemId, int rarity = -1, int amount = 1) { - if (!session.ItemMetadata.TryGet(itemId, out ItemMetadata? itemMetadata)) { - return null; - } - - if (rarity <= 0) { - if (itemMetadata.Option != null && itemMetadata.Option.ConstantId is < 6 and > 0) { - rarity = itemMetadata.Option.ConstantId; - } else { - rarity = 1; - } - } - - var item = new Item(itemMetadata, rarity, amount); - item.Stats = itemStatsCalc.GetStats(item); - item.Socket = itemStatsCalc.GetSockets(item); - - if (item.Appearance != null) { - item.Appearance.Color = GetColor(item.Metadata.Customize); - } - - return item; - } - - [Obsolete] - private EquipColor GetColor(ItemMetadataCustomize metadata) { - // Item has no color - if (metadata.ColorPalette == 0 || - !session.TableMetadata.ColorPaletteTable.Entries.TryGetValue(metadata.ColorPalette, out IReadOnlyDictionary? palette)) { - return default; - } - - // Item has random color - if (metadata.DefaultColorIndex < 0) { - // random entry from palette - int index = Random.Shared.Next(palette.Count); - ColorPaletteTable.Entry randomEntry = palette.Values.ElementAt(index); - return new EquipColor(randomEntry.Primary, randomEntry.Secondary, randomEntry.Tertiary, metadata.ColorPalette, index); - } - - // Item has specified color - if (palette.TryGetValue(metadata.DefaultColorIndex, out ColorPaletteTable.Entry? entry)) { - return new EquipColor(entry.Primary, entry.Secondary, entry.Tertiary, metadata.ColorPalette, metadata.DefaultColorIndex); - } - - return default; - } - public void Bind(Item item) { if (item.Transfer?.Bind(session.Player.Value.Character) == true) { session.Send(ItemInventoryPacket.UpdateItem(item)); From 8a3bf8d2930f102cd11e0404c7b5080040aad1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82ngelo=20Tadeucci?= Date: Tue, 22 Apr 2025 22:53:00 -0300 Subject: [PATCH 2/3] fix: ugc creation feat: delete extra cubes --- Maple2.Server.Core/Packets/UgcPacket.cs | 4 +-- .../Manager/Items/FurnishingManager.cs | 14 ++++++++++ .../FurnishingStorageHandler.cs | 28 +++++++++++++++++++ .../PacketHandlers/UgcHandler.cs | 15 ++++++++-- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs diff --git a/Maple2.Server.Core/Packets/UgcPacket.cs b/Maple2.Server.Core/Packets/UgcPacket.cs index 06d4d6ce4..27a6f23c5 100644 --- a/Maple2.Server.Core/Packets/UgcPacket.cs +++ b/Maple2.Server.Core/Packets/UgcPacket.cs @@ -76,7 +76,7 @@ public static ByteWriter ProfilePicture(Character character) { return pWriter; } - public static ByteWriter UpdateItem(int objectId, Item item, long createPrice, UgcType ugcType) { + public static ByteWriter UpdateItem(int objectId, long uid, Item item, long createPrice, UgcType ugcType) { var pWriter = Packet.Of(SendOp.Ugc); switch (ugcType) { case UgcType.Item: @@ -94,7 +94,7 @@ public static ByteWriter UpdateItem(int objectId, Item item, long createPrice, U pWriter.WriteInt(objectId); - pWriter.WriteLong(item.Uid); + pWriter.WriteLong(uid); pWriter.WriteInt(item.Id); pWriter.WriteInt(item.Amount); pWriter.WriteUnicodeString(item.Template!.Name); diff --git a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs index 56636c8a8..f183c8d1f 100644 --- a/Maple2.Server.Game/Manager/Items/FurnishingManager.cs +++ b/Maple2.Server.Game/Manager/Items/FurnishingManager.cs @@ -294,6 +294,20 @@ private bool RemoveInventory(long uid, [NotNullWhen(true)] out PlotCube? cube) { return true; } + public void RemoveItem(long itemUid) { + lock (session.Item) { + Item? item = storage.Get(itemUid); + if (item is null) { + return; + } + + item.Amount = 0; + + session.Send(FurnishingStoragePacket.Remove(itemUid)); + return; + } + } + public void SendStorageCount() { lock (session.Item) { session.Send(FurnishingStoragePacket.Count(storage.Count)); diff --git a/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs b/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs new file mode 100644 index 000000000..d81bef9c2 --- /dev/null +++ b/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs @@ -0,0 +1,28 @@ +using Maple2.PacketLib.Tools; +using Maple2.Server.Core.Constants; +using Maple2.Server.Core.PacketHandlers; +using Maple2.Server.Game.Session; + +namespace Maple2.Server.Game.PacketHandlers; + +public class FurnishingStorageHandler : PacketHandler{ + public override RecvOp OpCode => RecvOp.FurnishingStorage; + + private enum Command : byte { + Delete = 6, + } + + public override void Handle(GameSession session, IByteReader packet) { + var command = packet.Read(); + switch (command) { + case Command.Delete: + HandleDelete(session, packet); + return; + } + } + + private static void HandleDelete(GameSession session, IByteReader packet) { + long itemUid = packet.ReadLong(); + session.Item.Furnishing.RemoveItem(itemUid); + } +} diff --git a/Maple2.Server.Game/PacketHandlers/UgcHandler.cs b/Maple2.Server.Game/PacketHandlers/UgcHandler.cs index a971f8922..817317b67 100644 --- a/Maple2.Server.Game/PacketHandlers/UgcHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UgcHandler.cs @@ -448,15 +448,24 @@ void ConfirmItem() { } item.Template.Url = resource.Path; + long uid; // Dont create the item if it's a furniture since it's tied to account id if (info.Type is UgcType.Furniture) { - session.Item.Furnishing.AddCube(item); + uid = session.Item.Furnishing.AddCube(item); } else { - session.Item.Inventory.Add(item, notifyNew: true); + using GameStorage.Request db = session.GameStorage.Context(); + Item? newAdd = db.CreateItem(session.CharacterId, item); + if (newAdd == null) { + Logger.Error("Failed to create UGC item {ItemId}", item.Id); + return; + } + + uid = newAdd.Uid; + session.Item.Inventory.Add(newAdd, notifyNew: true); } - session.Send(UgcPacket.UpdateItem(session.Player.ObjectId, item, ugcMetadata.CreatePrice, info.Type)); + session.Send(UgcPacket.UpdateItem(session.Player.ObjectId, uid, item, ugcMetadata.CreatePrice, info.Type)); session.Send(UgcPacket.UpdatePath(resource)); } From 763df801d1d22d186af0cd95095918713636b162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82ngelo=20Tadeucci?= Date: Tue, 22 Apr 2025 22:55:49 -0300 Subject: [PATCH 3/3] format --- Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs b/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs index d81bef9c2..10f18f288 100644 --- a/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/FurnishingStorageHandler.cs @@ -5,7 +5,7 @@ namespace Maple2.Server.Game.PacketHandlers; -public class FurnishingStorageHandler : PacketHandler{ +public class FurnishingStorageHandler : PacketHandler { public override RecvOp OpCode => RecvOp.FurnishingStorage; private enum Command : byte {