diff options
| author | Shauren <shauren.trinity@gmail.com> | 2020-07-30 19:50:24 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2020-07-30 19:50:24 +0200 |
| commit | e94350fcc31cedb5a8140a71e2b2a03ab4125927 (patch) | |
| tree | b69c11790629ae1efb4ff9b408ccad0260c36069 /src | |
| parent | 2f0893d279ddab86ae7c3e4fd1d7a47b15e938f7 (diff) | |
Core/Mail: Refactor mail loading to execute 2 database queries instead of 1+mails.size()
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 166 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
| -rw-r--r-- | src/server/game/Handlers/SocialHandler.cpp | 1 |
4 files changed, 86 insertions, 87 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index bb68b65d3c8..dd161ef98cc 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -122,7 +122,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, itemEntry, ii.owner_guid, m.id FROM mail_items mi INNER JOIN mail m ON mi.mail_id = m.id LEFT JOIN item_instance ii ON mi.item_guid = ii.guid WHERE m.receiver = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, houseid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, houseid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -428,7 +428,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE itemEntry = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid WHERE itemEntry = ?", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c6cca97fcc2..80ac886585d 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4138,6 +4138,24 @@ 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->setUInt32(0, guid); + PreparedQueryResult resultItems = CharacterDatabase.Query(stmt); + + if (resultItems) + { + do + { + Field* fields = resultItems->Fetch(); + uint32 mailId = fields[14].GetUInt32(); + if (Item* mailItem = _LoadMailedItem(playerguid, nullptr, mailId, nullptr, fields)) + itemsByMail[mailId].push_back(mailItem); + + } while (resultItems->NextRow()); + } + do { Field* mailFields = resultMail->Fetch(); @@ -4173,41 +4191,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 item_guidlow = itemFields[11].GetUInt32(); - uint32 item_template = itemFields[12].GetUInt32(); - - ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_template); - if (!itemProto) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt32(0, item_guidlow); - trans->Append(stmt); - continue; - } - - Item* pItem = NewItemOrBag(itemProto); - if (!pItem->LoadFromDB(item_guidlow, playerguid, itemFields, item_template)) - { - pItem->FSetState(ITEM_REMOVED); - pItem->SaveToDB(trans); // it also deletes item object! - continue; - } + for (Item* item : itemsItr->second) + draft.AddItem(item); - draft.AddItem(pItem); - } - while (resultItems->NextRow()); - } + // MailDraft will take care of freeing memory + itemsByMail.erase(itemsItr); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); @@ -18403,61 +18394,54 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction& trans, uint32 zoneId, uint } // load mailed item which should receive current player -void Player::_LoadMailedItems(Mail* mail) +Item* Player::_LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields) { - // data needs to be at first place for Item::LoadFromDB - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); - stmt->setUInt32(0, mail->messageID); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (!result) - return; + ObjectGuid::LowType itemGuid = fields[11].GetUInt32(); + uint32 itemEntry = fields[12].GetUInt32(); - do + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry); + if (!proto) { - Field* fields = result->Fetch(); + TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item in mailed items (GUID: %u, Entry: %u) in mail (%u), deleted.", + player ? player->GetName().c_str() : "<unknown>", playerGuid.ToString().c_str(), itemGuid, itemEntry, mailId); - ObjectGuid::LowType itemGuid = fields[11].GetUInt32(); - uint32 itemTemplate = fields[12].GetUInt32(); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - mail->AddItem(itemGuid, itemTemplate); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); + stmt->setUInt32(0, itemGuid); + trans->Append(stmt); - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTemplate); + Item::DeleteFromDB(trans, itemGuid); - if (!proto) - { - TC_LOG_ERROR("entities.player", "Player '%s' (%s) has unknown item_template in mailed items (GUID: %u, Entry: %u) in mail (%u), deleted.", - GetName().c_str(), GetGUID().ToString().c_str(), itemGuid, itemTemplate, mail->messageID); + CharacterDatabase.CommitTransaction(trans); + return nullptr; + } - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); - stmt->setUInt32(0, itemGuid); - CharacterDatabase.Execute(stmt); + Item* item = NewItemOrBag(proto); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt32(0, itemGuid); - CharacterDatabase.Execute(stmt); - continue; - } + ObjectGuid ownerGuid = fields[13].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[13].GetUInt32()) : ObjectGuid::Empty; + if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) + { + TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: %u) in mail (%u) doesn't exist, deleted from mail.", itemGuid, mailId); - Item* item = NewItemOrBag(proto); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); + stmt->setUInt32(0, itemGuid); + CharacterDatabase.Execute(stmt); - if (!item->LoadFromDB(itemGuid, ObjectGuid(HighGuid::Player, fields[13].GetUInt32()), fields, itemTemplate)) - { - TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: %u) in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); + item->FSetState(ITEM_REMOVED); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); - stmt->setUInt32(0, itemGuid); - CharacterDatabase.Execute(stmt); + CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr); + item->SaveToDB(temp); // it also deletes item object ! + return nullptr; + } - item->FSetState(ITEM_REMOVED); + if (mail) + mail->AddItem(itemGuid, itemEntry); - CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr); - item->SaveToDB(temp); // it also deletes item object ! - continue; - } + if (player) + player->AddMItem(item); - AddMItem(item); - } - while (result->NextRow()); + return item; } void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery) @@ -18481,6 +18465,8 @@ void Player::_LoadMail() stmt->setUInt32(0, GetGUID().GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); + std::unordered_map<uint32, Mail*> mailById; + if (result) { do @@ -18494,14 +18480,13 @@ void Player::_LoadMail() m->receiver = fields[3].GetUInt32(); m->subject = fields[4].GetString(); m->body = fields[5].GetString(); - bool has_items = fields[6].GetBool(); - m->expire_time = time_t(fields[7].GetUInt32()); - m->deliver_time = time_t(fields[8].GetUInt32()); - m->money = fields[9].GetUInt32(); - m->COD = fields[10].GetUInt32(); - m->checked = fields[11].GetUInt8(); - m->stationery = fields[12].GetUInt8(); - m->mailTemplateId = fields[13].GetInt16(); + m->expire_time = time_t(fields[6].GetUInt32()); + m->deliver_time = time_t(fields[7].GetUInt32()); + m->money = fields[8].GetUInt32(); + m->COD = fields[9].GetUInt32(); + m->checked = fields[10].GetUInt8(); + m->stationery = fields[11].GetUInt8(); + m->mailTemplateId = fields[12].GetInt16(); if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) { @@ -18511,13 +18496,26 @@ void Player::_LoadMail() m->state = MAIL_STATE_UNCHANGED; - if (has_items) - _LoadMailedItems(m); - m_mail.push_back(m); + mailById[m->messageID] = m; } while (result->NextRow()); } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); + stmt->setUInt32(0, GetGUID().GetCounter()); + result = CharacterDatabase.Query(stmt); + + if (result) + { + do + { + Field* fields = result->Fetch(); + uint32 mailId = fields[14].GetUInt32(); + _LoadMailedItem(GetGUID(), this, mailId, mailById[mailId], fields); + } while (result->NextRow()); + } + m_mailsLoaded = true; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 85c2eb2c059..542cca2f29f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2229,7 +2229,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _LoadInventory(PreparedQueryResult result, uint32 timeDiff); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); - void _LoadMailedItems(Mail* mail); + static Item* _LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint32 mailId, Mail* mail, Field* fields); void _LoadQuestStatus(PreparedQueryResult result); void _LoadQuestStatusRewarded(PreparedQueryResult result); void _LoadDailyQuestStatus(PreparedQueryResult result); diff --git a/src/server/game/Handlers/SocialHandler.cpp b/src/server/game/Handlers/SocialHandler.cpp index 4271570e945..7b183355ead 100644 --- a/src/server/game/Handlers/SocialHandler.cpp +++ b/src/server/game/Handlers/SocialHandler.cpp @@ -22,6 +22,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" +#include "QueryCallback.h" #include "RBAC.h" #include "Realm.h" #include "SocialMgr.h" |
