diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-12-02 18:44:51 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-12-02 18:44:51 +0100 |
commit | f8cb710c7e6699c5542e9e435c3b7d2d8096669d (patch) | |
tree | a76b265b394b15052c5c80d1aefdb1fb1c584b14 /src | |
parent | f54e1fa3d525ad7e161546c09bb415506db5634e (diff) |
Core/Items: Fixed deleting items from db leaving orphaned transmog/artifact/modifier data when deleted from outside of player item update queue
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 28 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 136 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Mails/Mail.cpp | 6 |
7 files changed, 121 insertions, 77 deletions
diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp index 3d8fd01134c..dc539b82b85 100644 --- a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp @@ -177,20 +177,24 @@ void AzeriteItem::LoadAzeriteItemData(Player const* owner, AzeriteItemData& azer } } -void AzeriteItem::DeleteFromDB(CharacterDatabaseTransaction& trans) +void AzeriteItem::DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE); - stmt->setUInt64(0, GetGUID().GetCounter()); - trans->Append(stmt); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); - stmt->setUInt64(0, GetGUID().GetCounter()); - trans->Append(stmt); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); - stmt->setUInt64(0, GetGUID().GetCounter()); - trans->Append(stmt); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); +} +void AzeriteItem::DeleteFromDB(CharacterDatabaseTransaction& trans) +{ + AzeriteItem::DeleteFromDB(trans, GetGUID().GetCounter()); Item::DeleteFromDB(trans); } diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h index 9e69debf38d..4c1c882b0e1 100644 --- a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h @@ -35,6 +35,7 @@ public: void SaveToDB(CharacterDatabaseTransaction& trans) override; void LoadAzeriteItemData(Player const* owner, AzeriteItemData& azeriteItem); + static void DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType itemGuid); void DeleteFromDB(CharacterDatabaseTransaction& trans) override; uint32 GetLevel() const { return m_azeriteItemData->Level; } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 1dd190053d8..e71c5fb1060 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -379,7 +379,7 @@ void ItemAdditionalLoadInfo::Init(std::unordered_map<ObjectGuid::LowType, ItemAd } // 0 1 2 - // SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN ... + // SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN ... if (azeriteItemUnlockedEssencesResult) { do @@ -989,7 +989,31 @@ void Item::DeleteFromDB(CharacterDatabaseTransaction& trans, ObjectGuid::LowType { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt64(0, itemGuid); - trans->Append(stmt); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); + stmt->setUInt64(0, itemGuid); + CharacterDatabase.ExecuteOrAppend(trans, stmt); } void Item::DeleteFromDB(CharacterDatabaseTransaction& trans) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e6aff9ca6eb..acd895cb925 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3829,6 +3829,44 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe if (resultMail) { + std::unordered_map<uint32, std::vector<Item*>> itemsByMail; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); + stmt->setUInt64(0, guid); + PreparedQueryResult resultItems = CharacterDatabase.Query(stmt); + + if (resultItems) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_ARTIFACT); + stmt->setUInt64(0, guid); + PreparedQueryResult artifactResult = CharacterDatabase.Query(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE); + stmt->setUInt64(0, guid); + PreparedQueryResult azeriteResult = CharacterDatabase.Query(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_MILESTONE_POWER); + stmt->setUInt64(0, guid); + PreparedQueryResult azeriteItemMilestonePowersResult = CharacterDatabase.Query(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE); + stmt->setUInt64(0, guid); + PreparedQueryResult azeriteItemUnlockedEssencesResult = CharacterDatabase.Query(stmt); + + std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData; + ItemAdditionalLoadInfo::Init(&additionalData, artifactResult, azeriteResult, azeriteItemMilestonePowersResult, + azeriteItemUnlockedEssencesResult, azeriteEmpoweredItemResult); + + do + { + Field* fields = resultItems->Fetch(); + uint32 mailId = fields[44].GetUInt32(); + if (Item* mailItem = _LoadMailedItem(playerguid, nullptr, mailId, nullptr, fields, Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64()))) + itemsByMail[mailId].push_back(mailItem); + + } while (resultItems->NextRow()); + } + do { Field* mailFields = resultMail->Fetch(); @@ -3864,41 +3902,14 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe if (mailTemplateId) draft = MailDraft(mailTemplateId, false); // items are already included - if (has_items) + auto itemsItr = itemsByMail.find(mail_id); + if (itemsItr != itemsByMail.end()) { - // Data needs to be at first place for Item::LoadFromDB - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); - stmt->setUInt32(0, mail_id); - PreparedQueryResult resultItems = CharacterDatabase.Query(stmt); - if (resultItems) - { - do - { - Field* itemFields = resultItems->Fetch(); - ObjectGuid::LowType itemGuidLow = itemFields[0].GetUInt64(); - uint32 itemEntry = itemFields[1].GetUInt32(); - - ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemEntry); - if (!itemProto) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, itemGuidLow); - trans->Append(stmt); - continue; - } - - Item* item = NewItemOrBag(itemProto); - if (!item->LoadFromDB(itemGuidLow, playerguid, itemFields, itemEntry)) - { - item->FSetState(ITEM_REMOVED); - item->SaveToDB(trans); // it also deletes item object! - continue; - } - - draft.AddItem(item); - } - while (resultItems->NextRow()); - } + for (Item* item : itemsItr->second) + draft.AddItem(item); + + // MailDraft will take care of freeing memory + itemsByMail.erase(itemsItr); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); @@ -3910,6 +3921,11 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender, trans); } while (resultMail->NextRow()); + + // Free remaining items + for (auto&& kvp : itemsByMail) + for (Item* item : kvp.second) + delete item; } // Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet. @@ -19059,32 +19075,34 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint GetGUID().ToString().c_str(), GetName().c_str(), itemEntry); Item::DeleteFromInventoryDB(trans, itemGuid); Item::DeleteFromDB(trans, itemGuid); + AzeriteItem::DeleteFromDB(trans, itemGuid); } return item; } // load mailed item which should receive current player -void Player::_LoadMailedItem(Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData) +Item* Player::_LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData) { ObjectGuid::LowType itemGuid = fields[0].GetUInt64(); uint32 itemEntry = fields[1].GetUInt32(); - mail->AddItem(itemGuid, itemEntry); - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry); if (!proto) { TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item_template in mailed items (GUID: " UI64FMTD ", Entry: %u) in mail (%u), deleted.", - GetName().c_str(), GetGUID().ToString().c_str(), itemGuid, itemEntry, mail->messageID); + player ? player->GetName().c_str() : "<unknown>", playerGuid.ToString().c_str(), itemGuid, itemEntry, mailId); + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); stmt->setUInt64(0, itemGuid); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, itemGuid); - CharacterDatabase.Execute(stmt); - return; + Item::DeleteFromDB(trans, itemGuid); + AzeriteItem::DeleteFromDB(trans, itemGuid); + + CharacterDatabase.CommitTransaction(trans); + return nullptr; } Item* item = NewItemOrBag(proto); @@ -19092,7 +19110,7 @@ void Player::_LoadMailedItem(Mail* mail, Field* fields, ItemAdditionalLoadInfo* ObjectGuid ownerGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[43].GetUInt64()) : ObjectGuid::Empty; if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { - TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); + TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mailId); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); stmt->setUInt64(0, itemGuid); @@ -19102,21 +19120,27 @@ void Player::_LoadMailedItem(Mail* mail, Field* fields, ItemAdditionalLoadInfo* CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr); item->SaveToDB(temp); // it also deletes item object ! - return; + return nullptr; } if (addionalData) { if (item->GetTemplate()->GetArtifactID() && addionalData->Artifact) - item->LoadArtifactData(this, addionalData->Artifact->Xp, addionalData->Artifact->ArtifactAppearanceId, + item->LoadArtifactData(player, addionalData->Artifact->Xp, addionalData->Artifact->ArtifactAppearanceId, addionalData->Artifact->ArtifactTierId, addionalData->Artifact->ArtifactPowers); if (addionalData->AzeriteItem) if (AzeriteItem* azeriteItem = item->ToAzeriteItem()) - azeriteItem->LoadAzeriteItemData(this, *addionalData->AzeriteItem); + azeriteItem->LoadAzeriteItemData(player, *addionalData->AzeriteItem); } - AddMItem(item); + if (mail) + mail->AddItem(itemGuid, itemEntry); + + if (player) + player->AddMItem(item); + + return item; } void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery) @@ -19206,7 +19230,7 @@ void Player::_LoadMail() { Field* fields = result->Fetch(); uint32 mailId = fields[44].GetUInt32(); - _LoadMailedItem(mailById[mailId], fields, Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64())); + _LoadMailedItem(GetGUID(), this, mailId, mailById[mailId], fields, Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64())); } while (result->NextRow()); } @@ -20590,13 +20614,8 @@ void Player::_SaveInventory(CharacterDatabaseTransaction& trans) if (!item || item->GetState() == ITEM_NEW) continue; - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM); - stmt->setUInt64(0, item->GetGUID().GetCounter()); - trans->Append(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, item->GetGUID().GetCounter()); - trans->Append(stmt); + item->DeleteFromInventoryDB(trans); + item->DeleteFromDB(trans); m_items[i]->FSetState(ITEM_NEW); } @@ -20817,9 +20836,8 @@ void Player::_SaveMail(CharacterDatabaseTransaction& trans) { for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, itr2->item_guid); - trans->Append(stmt); + Item::DeleteFromDB(trans, itr2->item_guid); + AzeriteItem::DeleteFromDB(trans, itr2->item_guid); } } stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 68802a620d3..6a2592a0fe0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2513,7 +2513,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _LoadVoidStorage(PreparedQueryResult result); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); - void _LoadMailedItem(Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData); + static Item* _LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData); void _LoadQuestStatus(PreparedQueryResult result); void _LoadQuestStatusObjectives(PreparedQueryResult result); void _LoadQuestStatusRewarded(PreparedQueryResult result); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b37d3fadb49..61c7b168a40 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -18,6 +18,7 @@ #include "ObjectMgr.h" #include "ArenaTeamMgr.h" +#include "AzeriteItem.h" #include "Chat.h" #include "Containers.h" #include "DatabaseEnv.h" @@ -5867,12 +5868,12 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) // if it is mail from non-player, or if it's already return mail, it shouldn't be returned, but deleted if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED))) { + CharacterDatabaseTransaction nonTransactional(nullptr); // mail open and then not returned for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, itr2->item_guid); - CharacterDatabase.Execute(stmt); + Item::DeleteFromDB(nonTransactional, itr2->item_guid); + AzeriteItem::DeleteFromDB(nonTransactional, itr2->item_guid); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp index aaad1e4fcdf..53d232d20cc 100644 --- a/src/server/game/Mails/Mail.cpp +++ b/src/server/game/Mails/Mail.cpp @@ -129,11 +129,7 @@ void MailDraft::deleteIncludedItems(CharacterDatabaseTransaction& trans, bool in Item* item = mailItemIter->second; if (inDB) - { - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt64(0, item->GetGUID().GetCounter()); - trans->Append(stmt); - } + item->DeleteFromDB(trans); delete item; } |