mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-22 10:05:32 +01:00
Refactor mail loading to execute 2 database queries instead of 1+mails.size()
This commit is contained in:
@@ -128,7 +128,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, creationTime, 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, creationTime, 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, creationTime, 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);
|
||||
@@ -467,7 +467,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);
|
||||
|
||||
@@ -3833,6 +3833,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();
|
||||
@@ -3868,41 +3886,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();
|
||||
for (Item* item : itemsItr->second)
|
||||
draft.AddItem(item);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -18324,61 +18315,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);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM);
|
||||
stmt->setUInt32(0, itemGuid);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||
stmt->setUInt32(0, itemGuid);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item* item = NewItemOrBag(proto);
|
||||
|
||||
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);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
|
||||
stmt->setUInt32(0, itemGuid);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
|
||||
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
|
||||
item->SaveToDB(temp); // it also deletes item object !
|
||||
continue;
|
||||
}
|
||||
|
||||
AddMItem(item);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
return nullptr;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
Item* item = NewItemOrBag(proto);
|
||||
|
||||
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);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
|
||||
stmt->setUInt32(0, itemGuid);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
item->FSetState(ITEM_REMOVED);
|
||||
|
||||
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
|
||||
item->SaveToDB(temp); // it also deletes item object !
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mail)
|
||||
mail->AddItem(itemGuid, itemEntry);
|
||||
|
||||
if (player)
|
||||
player->AddMItem(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery)
|
||||
@@ -18402,6 +18386,8 @@ void Player::_LoadMail()
|
||||
stmt->setUInt32(0, GetGUID().GetCounter());
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
std::unordered_map<uint32, Mail*> mailById;
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
@@ -18415,14 +18401,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].GetUInt64();
|
||||
m->COD = fields[10].GetUInt64();
|
||||
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))
|
||||
{
|
||||
@@ -18431,14 +18416,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2467,7 +2467,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void _LoadVoidStorage(PreparedQueryResult result);
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user