diff --git a/Source/Game/Entities/Item/AzeriteItem.cs b/Source/Game/Entities/Item/AzeriteItem.cs index 0bd24b7cd..286408b39 100644 --- a/Source/Game/Entities/Item/AzeriteItem.cs +++ b/Source/Game/Entities/Item/AzeriteItem.cs @@ -188,20 +188,24 @@ namespace Game.Entities } public override void DeleteFromDB(SQLTransaction trans) + { + DeleteFromDB(trans, GetGUID().GetCounter()); + base.DeleteFromDB(trans); + } + + public new static void DeleteFromDB(SQLTransaction trans, ulong itemGuid) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE); - stmt.AddValue(0, GetGUID().GetCounter()); - trans.Append(stmt); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); - stmt.AddValue(0, GetGUID().GetCounter()); - trans.Append(stmt); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); - stmt.AddValue(0, GetGUID().GetCounter()); - trans.Append(stmt); - - base.DeleteFromDB(trans); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); } public uint GetLevel() { return m_azeriteItemData.Level; } diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 3208414b9..e0cbdf19b 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -617,7 +617,31 @@ namespace Game.Entities { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); stmt.AddValue(0, itemGuid); - trans.Append(stmt); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_GEMS); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_TRANSMOG); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_ARTIFACT); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_ARTIFACT_POWERS); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_MODIFIERS); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT); + stmt.AddValue(0, itemGuid); + DB.Characters.ExecuteOrAppend(trans, stmt); } public virtual void DeleteFromDB(SQLTransaction trans) diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 2134df96b..7eb5e7250 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -325,6 +325,7 @@ namespace Game.Entities GetGUID().ToString(), GetName(), itemEntry); Item.DeleteFromInventoryDB(trans, itemGuid); Item.DeleteFromDB(trans, itemGuid); + AzeriteItem.DeleteFromDB(trans, itemGuid); } return item; } @@ -1204,40 +1205,42 @@ namespace Game.Entities do { uint mailId = result.Read(44); - _LoadMailedItem(mailById[mailId], result.GetFields(), additionalData.LookupByKey(result.Read(0))); + _LoadMailedItem(GetGUID(), this, mailId, mailById[mailId], result.GetFields(), additionalData.LookupByKey(result.Read(0))); } while (result.NextRow()); } m_mailsLoaded = true; } - void _LoadMailedItem(Mail mail, SQLFields fields, ItemAdditionalLoadInfo additionalLoadInfo) + + static Item _LoadMailedItem(ObjectGuid playerGuid, Player player, uint mailId, Mail mail, SQLFields fields, ItemAdditionalLoadInfo addionalData) { ulong itemGuid = fields.Read(0); uint itemEntry = fields.Read(1); - mail.AddItem(itemGuid, itemEntry); - ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemEntry); if (proto == null) { - Log.outError(LogFilter.Player, "Player {0} has unknown item_template (ProtoType) in mailed items(GUID: {1} template: {2}) in mail ({3}), deleted.", GetGUID().ToString(), itemGuid, itemEntry, mail.messageID); + Log.outError(LogFilter.Player, $"Player {(player != null ? player.GetName() : "")} ({playerGuid.ToString()}) has unknown item_template (ProtoType) in mailed items(GUID: {itemGuid} template: {itemEntry}) in mail ({mailId}), deleted."); + + SQLTransaction trans = new SQLTransaction(); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_INVALID_MAIL_ITEM); stmt.AddValue(0, itemGuid); - DB.Characters.Execute(stmt); + trans.Append(stmt); - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, itemGuid); - DB.Characters.Execute(stmt); - return; + Item.DeleteFromDB(trans, itemGuid); + AzeriteItem.DeleteFromDB(trans, itemGuid); + + DB.Characters.CommitTransaction(trans); + return null; } Item item = Bag.NewItemOrBag(proto); ObjectGuid ownerGuid = fields.Read(43) != 0 ? ObjectGuid.Create(HighGuid.Player, fields.Read(43)) : ObjectGuid.Empty; if (!item.LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { - Log.outError(LogFilter.Player, "Player:_LoadMailedItem - Item in mail ({0}) doesn't exist !!!! - item guid: {1}, deleted from mail", mail.messageID, itemGuid); + Log.outError(LogFilter.Player, $"Player._LoadMailedItems: Item (GUID: {itemGuid}) in mail ({mailId}) doesn't exist, deleted from mail."); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM); stmt.AddValue(0, itemGuid); @@ -1246,24 +1249,30 @@ namespace Game.Entities item.FSetState(ItemUpdateState.Removed); item.SaveToDB(null); // it also deletes item object ! - return; + return null; } - if (additionalLoadInfo != null) + if (addionalData != null) { - if (item.GetTemplate().GetArtifactID() != 0 && additionalLoadInfo.Artifact != null) - item.LoadArtifactData(this, additionalLoadInfo.Artifact.Xp, additionalLoadInfo.Artifact.ArtifactAppearanceId, - additionalLoadInfo.Artifact.ArtifactTierId, additionalLoadInfo.Artifact.ArtifactPowers); + if (item.GetTemplate().GetArtifactID() != 0 && addionalData.Artifact != null) + item.LoadArtifactData(player, addionalData.Artifact.Xp, addionalData.Artifact.ArtifactAppearanceId, + addionalData.Artifact.ArtifactTierId, addionalData.Artifact.ArtifactPowers); - if (additionalLoadInfo.AzeriteItem != null) + if (addionalData.AzeriteItem != null) { AzeriteItem azeriteItem = item.ToAzeriteItem(); if (azeriteItem != null) - azeriteItem.LoadAzeriteItemData(this, additionalLoadInfo.AzeriteItem); + azeriteItem.LoadAzeriteItemData(player, addionalData.AzeriteItem); } } - AddMItem(item); + if (mail != null) + mail.AddItem(itemGuid, itemEntry); + + if (player != null) + player.AddMItem(item); + + return item; } void _LoadDeclinedNames(SQLResult result) { @@ -1479,13 +1488,8 @@ namespace Game.Entities if (item == null || item.GetState() == ItemUpdateState.New) continue; - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_INVENTORY_BY_ITEM); - stmt.AddValue(0, item.GetGUID().GetCounter()); - trans.Append(stmt); - - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, item.GetGUID().GetCounter()); - trans.Append(stmt); + item.DeleteFromInventoryDB(trans); + item.DeleteFromDB(trans); m_items[i].FSetState(ItemUpdateState.New); } @@ -2073,11 +2077,10 @@ namespace Game.Entities { if (m.HasItems()) { - foreach (var id in m.items) + foreach (var mailItemInfo in m.items) { - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, id.item_guid); - trans.Append(stmt); + Item.DeleteFromDB(trans, mailItemInfo.item_guid); + AzeriteItem.DeleteFromDB(trans, mailItemInfo.item_guid); } } stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_BY_ID); @@ -3636,6 +3639,43 @@ namespace Game.Entities SQLResult resultMail = DB.Characters.Query(stmt); if (!resultMail.IsEmpty()) { + MultiMap itemsByMail = new MultiMap(); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS); + stmt.AddValue(0, guid); + SQLResult resultItems = DB.Characters.Query(stmt); + + if (!resultItems.IsEmpty()) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_ARTIFACT); + stmt.AddValue(0, guid); + SQLResult artifactResult = DB.Characters.Query(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE); + stmt.AddValue(0, guid); + SQLResult azeriteResult = DB.Characters.Query(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, guid); + SQLResult azeriteItemMilestonePowersResult = DB.Characters.Query(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, guid); + SQLResult azeriteItemUnlockedEssencesResult = DB.Characters.Query(stmt); + + Dictionary additionalData = new Dictionary(); + ItemAdditionalLoadInfo.Init(additionalData, artifactResult, azeriteResult, azeriteItemMilestonePowersResult, azeriteItemUnlockedEssencesResult); + + do + { + uint mailId = resultItems.Read(44); + Item mailItem = _LoadMailedItem(playerGuid, null, mailId, null, resultItems.GetFields(), additionalData.LookupByKey(resultItems.Read(0))); + if (mailItem != null) + itemsByMail.Add(mailId, mailItem); + + } while (resultItems.NextRow()); + } + do { uint mail_id = resultMail.Read(0); @@ -3669,40 +3709,13 @@ namespace Game.Entities if (mailTemplateId != 0) draft = new MailDraft(mailTemplateId, false); // items are already included - if (has_items) + var itemsList = itemsByMail.LookupByKey(mail_id); + if (itemsList != null) { - // Data needs to be at first place for Item.LoadFromDB - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS); - stmt.AddValue(0, mail_id); - SQLResult resultItems = DB.Characters.Query(stmt); - if (!resultItems.IsEmpty()) - { - do - { - ulong itemGuidLow = resultItems.Read(0); - uint itemEntry = resultItems.Read(1); + foreach (Item item in itemsList) + draft.AddItem(item); - ItemTemplate itemProto = Global.ObjectMgr.GetItemTemplate(itemEntry); - if (itemProto == null) - { - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, itemGuidLow); - trans.Append(stmt); - continue; - } - - Item item = Bag.NewItemOrBag(itemProto); - if (!item.LoadFromDB(itemGuidLow, ObjectGuid.Create(HighGuid.Player, guid), resultItems.GetFields(), itemEntry)) - { - item.FSetState(ItemUpdateState.Removed); - item.SaveToDB(trans); // it also deletes item object! - continue; - } - - draft.AddItem(item); - } - while (resultItems.NextRow()); - } + itemsByMail.Remove(mail_id); } stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM_BY_ID); @@ -3714,6 +3727,10 @@ namespace Game.Entities draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender, trans); } while (resultMail.NextRow()); + + // Free remaining items + foreach (var pair in itemsByMail) + pair.Value.Dispose(); } // Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet. diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index a36af9e9f..39a8a5be7 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -8749,9 +8749,8 @@ namespace Game // mail open and then not returned foreach (var itemInfo in m.items) { - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, itemInfo.item_guid); - DB.Characters.Execute(stmt); + Item.DeleteFromDB(null, itemInfo.item_guid); + AzeriteItem.DeleteFromDB(null, itemInfo.item_guid); } stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM_BY_ID); diff --git a/Source/Game/Mails/MailDraft.cs b/Source/Game/Mails/MailDraft.cs index d8084f950..76a8e8808 100644 --- a/Source/Game/Mails/MailDraft.cs +++ b/Source/Game/Mails/MailDraft.cs @@ -82,11 +82,7 @@ namespace Game.Mails foreach (var item in m_items.Values) { if (inDB) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, item.GetGUID().GetCounter()); - trans.Append(stmt); - } + item.DeleteFromDB(trans); } m_items.Clear();