fix(Core/Mail): cleanup pending auction sale mail (#6022)

This commit is contained in:
UltraNix
2021-06-23 12:46:48 +02:00
committed by GitHub
parent 77ad79c928
commit a9b2ddba7a
12 changed files with 160 additions and 80 deletions
@@ -0,0 +1,4 @@
INSERT INTO `version_db_characters` (`sql_rev`) VALUES ('1621780938723425400');
ALTER TABLE `mail`
ADD COLUMN `auctionId` INT DEFAULT 0 NOT NULL AFTER `checked`;
@@ -109,12 +109,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, houseid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, houseid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_AUCTION_BID, "UPDATE auctionhouse SET buyguid = ?, lastbid = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_AUCTION_BID, "UPDATE auctionhouse SET buyguid = ?, lastbid = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_MAIL, "INSERT INTO mail(id, messageType, stationery, mailTemplateId, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_MAIL, "INSERT INTO mail(id, messageType, stationery, mailTemplateId, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, auctionId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_MAIL_BY_ID, "DELETE FROM mail WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL_BY_ID, "DELETE FROM mail WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_MAIL_ITEM, "INSERT INTO mail_items(mail_id, item_guid, receiver) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_MAIL_ITEM, "INSERT INTO mail_items(mail_id, item_guid, receiver) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_INVALID_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_EXPIRED_MAIL, "SELECT id, messageType, sender, receiver, has_items, expire_time, cod, checked, mailTemplateId FROM mail WHERE expire_time < ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_EXPIRED_MAIL, "SELECT id, messageType, sender, receiver, has_items, expire_time, cod, checked, mailTemplateId, auctionId FROM mail WHERE expire_time < ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS, "SELECT item_guid, itemEntry, mail_id FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid LEFT JOIN mail mm ON mi.mail_id = mm.id WHERE mm.id IS NOT NULL AND mm.expire_time < ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS, "SELECT item_guid, itemEntry, mail_id FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid LEFT JOIN mail mm ON mi.mail_id = mm.id WHERE mm.id IS NOT NULL AND mm.expire_time < ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_UPD_MAIL_RETURNED, "UPDATE mail SET sender = ?, receiver = ?, expire_time = ?, deliver_time = ?, cod = 0, checked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_MAIL_RETURNED, "UPDATE mail SET sender = ?, receiver = ?, expire_time = ?, deliver_time = ?, cod = 0, checked = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_MAIL_ITEM_RECEIVER, "UPDATE mail_items SET receiver = ? WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_MAIL_ITEM_RECEIVER, "UPDATE mail_items SET receiver = ? WHERE item_guid = ?", CONNECTION_ASYNC);
@@ -402,7 +402,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", 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_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid = ? AND type = ? LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid = ? AND type = ? LIMIT 1", 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 = ? AND deliver_time <= ? ORDER BY id DESC LIMIT 50", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId, auctionId FROM mail WHERE receiver = ? AND deliver_time <= ? ORDER BY id DESC LIMIT 50", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND deliver_time > ? AND (checked & 1) = 0 LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND deliver_time > ? AND (checked & 1) = 0 LIMIT 1", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?", CONNECTION_ASYNC); 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_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);
@@ -135,7 +135,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabas
} }
if (sendMail) // can be changed in the hook if (sendMail) // can be changed in the hook
MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, 0, 0)) MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout))
.AddItem(pItem) .AddItem(pItem)
.SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED); .SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED);
} }
@@ -151,9 +151,16 @@ void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, Characte
if (owner || owner_accId) if (owner || owner_accId)
{ {
sScriptMgr->OnBeforeAuctionHouseMgrSendAuctionSalePendingMail(this, auction, owner, owner_accId, sendMail); sScriptMgr->OnBeforeAuctionHouseMgrSendAuctionSalePendingMail(this, auction, owner, owner_accId, sendMail);
uint32 deliveryDelay = sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY);
ByteBuffer timePacker;
timePacker.AppendPackedTime(time_t(time(nullptr) + deliveryDelay));
if (sendMail) // can be changed in the hook if (sendMail) // can be changed in the hook
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut())) MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING),
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED); AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut(), deliveryDelay, timePacker.read<uint32>()))
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, 0, 0, false, true, -static_cast<int32>(auction->Id));
} }
} }
@@ -183,7 +190,7 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, Character
if (sendMail) // can be changed in the hook if (sendMail) // can be changed in the hook
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut())) MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
.AddMoney(profit) .AddMoney(profit)
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY)); .SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), 0, false, true, auction->Id);
if (auction->bid >= 500 * GOLD) if (auction->bid >= 500 * GOLD)
if (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(auction->bidder.GetCounter())) if (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(auction->bidder.GetCounter()))
@@ -222,7 +229,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, CharacterDat
owner->GetSession()->SendAuctionOwnerNotification(auction); owner->GetSession()->SendAuctionOwnerNotification(auction);
if (sendMail) // can be changed in the hook if (sendMail) // can be changed in the hook
MailDraft(auction->BuildAuctionMailSubject(AUCTION_EXPIRED), AuctionEntry::BuildAuctionMailBody(ObjectGuid::Empty, 0, auction->buyout, auction->deposit, 0)) MailDraft(auction->BuildAuctionMailSubject(AUCTION_EXPIRED), AuctionEntry::BuildAuctionMailBody(ObjectGuid::Empty, 0, auction->buyout, auction->deposit))
.AddItem(pItem) .AddItem(pItem)
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, 0); .SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED, 0);
} }
@@ -268,7 +275,7 @@ void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, Ch
{ {
sScriptMgr->OnBeforeAuctionHouseMgrSendAuctionCancelledToBidderMail(this, auction, bidder, bidder_accId, sendMail); sScriptMgr->OnBeforeAuctionHouseMgrSendAuctionCancelledToBidderMail(this, auction, bidder, bidder_accId, sendMail);
if (sendMail) // can be changed in the hook if (sendMail) // can be changed in the hook
MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELLED_TO_BIDDER), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, 0)) MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELLED_TO_BIDDER), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit))
.AddMoney(auction->bid) .AddMoney(auction->bid)
.SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED); .SendMailTo(trans, MailReceiver(bidder, auction->bidder.GetCounter()), auction, MAIL_CHECK_MASK_COPIED);
} }
@@ -777,12 +784,13 @@ std::string AuctionEntry::BuildAuctionMailSubject(MailAuctionAnswers response) c
return strm.str(); return strm.str();
} }
std::string AuctionEntry::BuildAuctionMailBody(ObjectGuid guid, uint32 bid, uint32 buyout, uint32 deposit, uint32 cut) std::string AuctionEntry::BuildAuctionMailBody(ObjectGuid guid, uint32 bid, uint32 buyout, uint32 deposit /*= 0*/, uint32 cut /*= 0*/, uint32 moneyDelay /*= 0*/, uint32 eta /*= 0*/)
{ {
std::ostringstream strm; std::ostringstream strm;
strm.width(16); strm.width(16);
strm << std::right << std::hex << guid.GetRawValue(); strm << std::right << std::hex << guid.GetRawValue();
strm << std::dec << ':' << bid << ':' << buyout; strm << std::dec << ':' << bid << ':' << buyout;
strm << ':' << deposit << ':' << cut; strm << ':' << deposit << ':' << cut;
strm << ':' << moneyDelay << ':' << eta;
return strm.str(); return strm.str();
} }
@@ -84,7 +84,7 @@ struct AuctionEntry
void SaveToDB(CharacterDatabaseTransaction trans) const; void SaveToDB(CharacterDatabaseTransaction trans) const;
bool LoadFromDB(Field* fields); bool LoadFromDB(Field* fields);
[[nodiscard]] std::string BuildAuctionMailSubject(MailAuctionAnswers response) const; [[nodiscard]] std::string BuildAuctionMailSubject(MailAuctionAnswers response) const;
static std::string BuildAuctionMailBody(ObjectGuid guid, uint32 bid, uint32 buyout, uint32 deposit, uint32 cut); static std::string BuildAuctionMailBody(ObjectGuid guid, uint32 bid, uint32 buyout, uint32 deposit = 0, uint32 cut = 0, uint32 moneyDelay = 0, uint32 eta = 0);
}; };
//this class is used as auctionhouse instance //this class is used as auctionhouse instance
+69 -12
View File
@@ -847,7 +847,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_mailsUpdated = false; m_mailsUpdated = false;
unReadMails = 0; unReadMails = 0;
m_nextMailDelivereTime = 0; m_nextMailDelivereTime = time_t(0);
m_resetTalentsCost = 0; m_resetTalentsCost = 0;
m_resetTalentsTime = 0; m_resetTalentsTime = 0;
@@ -1605,7 +1605,7 @@ void Player::Update(uint32 p_time)
++unReadMails; ++unReadMails;
// It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated) // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated)
m_nextMailDelivereTime = 0; m_nextMailDelivereTime = time_t(0);
} }
// Update cinematic location, if 500ms have passed and we're doing a cinematic now. // Update cinematic location, if 500ms have passed and we're doing a cinematic now.
@@ -3736,18 +3736,18 @@ void Player::UpdateNextMailTimeAndUnreads()
//Get the next delivery time //Get the next delivery time
CharacterDatabasePreparedStatement* stmtNextDeliveryTime = CharacterDatabase.GetPreparedStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME); CharacterDatabasePreparedStatement* stmtNextDeliveryTime = CharacterDatabase.GetPreparedStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME);
stmtNextDeliveryTime->setUInt32(0, GetGUID().GetCounter()); stmtNextDeliveryTime->setUInt32(0, GetGUID().GetCounter());
stmtNextDeliveryTime->setUInt64(1, cTime); stmtNextDeliveryTime->setUInt32(1, uint32(cTime));
PreparedQueryResult resultNextDeliveryTime = CharacterDatabase.Query(stmtNextDeliveryTime); PreparedQueryResult resultNextDeliveryTime = CharacterDatabase.Query(stmtNextDeliveryTime);
if (resultNextDeliveryTime) if (resultNextDeliveryTime)
{ {
Field* fields = resultNextDeliveryTime->Fetch(); Field* fields = resultNextDeliveryTime->Fetch();
m_nextMailDelivereTime = fields[0].GetUInt64(); m_nextMailDelivereTime = time_t(fields[0].GetUInt32());
} }
//Get unread mails count //Get unread mails count
CharacterDatabasePreparedStatement* stmtUnreadAmount = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH); CharacterDatabasePreparedStatement* stmtUnreadAmount = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH);
stmtUnreadAmount->setUInt32(0, GetGUID().GetCounter()); stmtUnreadAmount->setUInt32(0, GetGUID().GetCounter());
stmtUnreadAmount->setUInt64(1, cTime); stmtUnreadAmount->setUInt32(1, uint32(cTime));
PreparedQueryResult resultUnreadAmount = CharacterDatabase.Query(stmtUnreadAmount); PreparedQueryResult resultUnreadAmount = CharacterDatabase.Query(stmtUnreadAmount);
if (resultUnreadAmount) if (resultUnreadAmount)
{ {
@@ -19148,13 +19148,13 @@ void Player::_LoadMail()
} }
//This should in theory always be < 100 //This should in theory always be < 100
for (PlayerMails::iterator itr = GetMailBegin(); itr != GetMailEnd();) for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end();)
{ {
Mail* m = *itr; Mail* mail = *itr;
m_mailCache.erase(itr); itr = m_mailCache.erase(itr);
if(m)
delete m; if (mail)
itr = GetMailBegin(); delete mail;
} }
// Delete mailed items aswell // Delete mailed items aswell
@@ -19162,13 +19162,19 @@ void Player::_LoadMail()
for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
delete iter->second; delete iter->second;
std::set<uint32> pendingAuctions;
std::unordered_map<uint32, Mail*> pendingAuctionMails;
mMitems.clear(); mMitems.clear();
//Now load the new ones //Now load the new ones
m_mailCache.clear(); m_mailCache.clear();
CharacterDatabaseTransaction pendingAuctionsTrans = CharacterDatabase.BeginTransaction();
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
stmt->setUInt32(0, GetGUID().GetCounter()); stmt->setUInt32(0, GetGUID().GetCounter());
stmt->setUInt64(1, time(nullptr)); stmt->setUInt32(1, uint32(time(nullptr)));
PreparedQueryResult result = CharacterDatabase.Query(stmt); PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result) if (result)
{ {
@@ -19192,6 +19198,7 @@ void Player::_LoadMail()
m->checked = fields[11].GetUInt8(); m->checked = fields[11].GetUInt8();
m->stationery = fields[12].GetUInt8(); m->stationery = fields[12].GetUInt8();
m->mailTemplateId = fields[13].GetInt16(); m->mailTemplateId = fields[13].GetInt16();
m->auctionId = fields[14].GetInt32();
if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId))
{ {
@@ -19204,10 +19211,60 @@ void Player::_LoadMail()
if (has_items) if (has_items)
_LoadMailedItems(m); _LoadMailedItems(m);
// Do not load expired pending sale mail if there is already delivery auction mail
if (m->auctionId < 0 && m->expire_time <= time(nullptr))
{
uint32 auctionId = std::abs(m->auctionId);
if (pendingAuctions.count(auctionId))
{
CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
stmt2->setUInt32(0, m->messageID);
pendingAuctionsTrans->Append(stmt2);
if (totalMailCount > 0)
--totalMailCount;
if (unReadMails > 0 && (m->checked & MAIL_CHECK_MASK_READ) == 0)
--unReadMails;
delete m;
continue;
}
pendingAuctionMails[auctionId] = m;
}
else if (m->auctionId > 0)
pendingAuctions.insert(m->auctionId);
m_mailCache.push_back(m); m_mailCache.push_back(m);
} }
while (result->NextRow()); while (result->NextRow());
} }
for (auto itr : pendingAuctionMails)
{
uint32 auctionId = itr.first;
if (pendingAuctions.count(auctionId))
{
Mail* mail = itr.second;
CharacterDatabasePreparedStatement* stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
stmt2->setUInt32(0, mail->messageID);
pendingAuctionsTrans->Append(stmt2);
if (totalMailCount > 0)
--totalMailCount;
if (unReadMails > 0 && (mail->checked & MAIL_CHECK_MASK_READ) == 0)
--unReadMails;
m_mailCache.erase(std::remove(m_mailCache.begin(), m_mailCache.end(), mail));
delete mail;
}
}
CharacterDatabase.CommitTransaction(pendingAuctionsTrans);
} }
void Player::LoadPet() void Player::LoadPet()
+1 -2
View File
@@ -1653,8 +1653,7 @@ public:
uint32 GetMailCacheSize() { return m_mailCache.size();} uint32 GetMailCacheSize() { return m_mailCache.size();}
Mail* GetMail(uint32 id); Mail* GetMail(uint32 id);
PlayerMails::iterator GetMailBegin() { return m_mailCache.begin();} PlayerMails const& GetMails() const { return m_mailCache; }
PlayerMails::iterator GetMailEnd() { return m_mailCache.end();}
/*********************************************************/ /*********************************************************/
/*** MAILED ITEMS SYSTEM ***/ /*** MAILED ITEMS SYSTEM ***/
+6 -5
View File
@@ -5681,14 +5681,14 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
time_t curTime = time(nullptr); time_t curTime = time(nullptr);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL);
stmt->setUInt32(0, curTime); stmt->setUInt32(0, uint32(curTime));
PreparedQueryResult result = CharacterDatabase.Query(stmt); PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result) if (!result)
return; return;
std::map<uint32 /*messageId*/, MailItemInfoVec> itemsCache; std::map<uint32 /*messageId*/, MailItemInfoVec> itemsCache;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS);
stmt->setUInt32(0, curTime); stmt->setUInt32(0, uint32(curTime));
if (PreparedQueryResult items = CharacterDatabase.Query(stmt)) if (PreparedQueryResult items = CharacterDatabase.Query(stmt))
{ {
MailItemInfo item; MailItemInfo item;
@@ -5714,10 +5714,11 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
m->receiver = fields[3].GetUInt32(); m->receiver = fields[3].GetUInt32();
bool has_items = fields[4].GetBool(); bool has_items = fields[4].GetBool();
m->expire_time = time_t(fields[5].GetUInt32()); m->expire_time = time_t(fields[5].GetUInt32());
m->deliver_time = 0; m->deliver_time = time_t(0);
m->COD = fields[6].GetUInt32(); m->COD = fields[6].GetUInt32();
m->checked = fields[7].GetUInt8(); m->checked = fields[7].GetUInt8();
m->mailTemplateId = fields[8].GetInt16(); m->mailTemplateId = fields[8].GetInt16();
m->auctionId = fields[9].GetInt32();
Player* player = nullptr; Player* player = nullptr;
if (serverUp) if (serverUp)
@@ -5755,8 +5756,8 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL_RETURNED); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL_RETURNED);
stmt->setUInt32(0, m->receiver); stmt->setUInt32(0, m->receiver);
stmt->setUInt32(1, m->sender); stmt->setUInt32(1, m->sender);
stmt->setUInt32(2, curTime + 30 * DAY); stmt->setUInt32(2, uint32(curTime + 30 * DAY));
stmt->setUInt32(3, curTime); stmt->setUInt32(3, uint32(curTime));
stmt->setUInt8 (4, uint8(MAIL_CHECK_MASK_RETURNED)); stmt->setUInt8 (4, uint8(MAIL_CHECK_MASK_RETURNED));
stmt->setUInt32(5, m->messageID); stmt->setUInt32(5, m->messageID);
CharacterDatabase.Execute(stmt); CharacterDatabase.Execute(stmt);
@@ -550,7 +550,7 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData)
} }
// item will deleted or added to received mail list // item will deleted or added to received mail list
MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELED), AuctionEntry::BuildAuctionMailBody(ObjectGuid::Empty, 0, auction->buyout, auction->deposit, 0)) MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELED), AuctionEntry::BuildAuctionMailBody(ObjectGuid::Empty, 0, auction->buyout, auction->deposit))
.AddItem(pItem) .AddItem(pItem)
.SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED); .SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED);
} }
@@ -113,12 +113,12 @@ bool LoginQueryHolder::Initialize()
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT);
stmt->setUInt32(0, lowGuid); stmt->setUInt32(0, lowGuid);
stmt->setUInt64(1, uint64(time(nullptr))); stmt->setUInt32(1, uint32(time(nullptr)));
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT, stmt); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD);
stmt->setUInt32(0, lowGuid); stmt->setUInt32(0, lowGuid);
stmt->setUInt64(1, uint64(time(nullptr))); stmt->setUInt32(1, uint32(time(nullptr)));
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_UNREAD_COUNT, stmt); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_UNREAD_COUNT, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE);
+48 -43
View File
@@ -588,54 +588,59 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
Player* player = _player; Player* player = _player;
player->_LoadMail(); player->_LoadMail();
uint32 mailsCount = 0; // real send to client mails amount // real mails amount uint8 mailsCount = 0;
uint32 realCount = 0;
WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size
data << uint32(0); // real mail's count data << uint32(0); // real mail's count
data << uint8(0); // mail's count data << uint8(0); // mail's count
time_t cur_time = time(nullptr); time_t cur_time = time(nullptr);
for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) for (Mail const* mail : player->GetMails())
{ {
// prevent client storage overflow // prevent client storage overflow
if (mailsCount >= MAX_INBOX_CLIENT_CAPACITY) if (mailsCount >= MAX_INBOX_CLIENT_CAPACITY)
{ {
break; ++realCount;
continue;
} }
// skip deleted or not delivered (deliver delay not expired) mails // skip deleted or not delivered (deliver delay not expired) mails
if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) if (mail->state == MAIL_STATE_DELETED || cur_time < mail->deliver_time)
continue;
uint8 item_count = uint8((*itr)->items.size()); // max count is MAX_MAIL_ITEMS (12)
size_t next_mail_size = 2 + 4 + 1 + ((*itr)->messageType == MAIL_NORMAL ? 8 : 4) + 4 * 8 + ((*itr)->subject.size() + 1) + ((*itr)->body.size() + 1) + 1 + item_count * (1 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * 3 * 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1);
if (data.wpos() + next_mail_size > MAX_NETCLIENT_PACKET_SIZE)
{ {
continue; continue;
} }
data << uint16(next_mail_size); // Message size uint8 item_count = uint8(mail->items.size()); // max count is MAX_MAIL_ITEMS (12)
data << uint32((*itr)->messageID); // Message ID
data << uint8((*itr)->messageType); // Message Type
switch ((*itr)->messageType) size_t next_mail_size = 2 + 4 + 1 + (mail->messageType == MAIL_NORMAL ? 8 : 4) + 4 * 8 + (mail->subject.size() + 1) + (mail->body.size() + 1) + 1 + item_count * (1 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * 3 * 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1);
if (data.wpos() + next_mail_size > MAX_NETCLIENT_PACKET_SIZE)
{
++realCount;
continue;
}
data << uint16(next_mail_size); // Message size
data << uint32(mail->messageID); // Message ID
data << uint8(mail->messageType); // Message Type
switch (mail->messageType)
{ {
case MAIL_NORMAL: // sender guid case MAIL_NORMAL: // sender guid
data << ObjectGuid::Create<HighGuid::Player>((*itr)->sender); data << ObjectGuid::Create<HighGuid::Player>(mail->sender);
break; break;
case MAIL_CREATURE: case MAIL_CREATURE:
case MAIL_GAMEOBJECT: case MAIL_GAMEOBJECT:
case MAIL_AUCTION: case MAIL_AUCTION:
case MAIL_CALENDAR: case MAIL_CALENDAR:
data << uint32((*itr)->sender); // creature/gameobject entry, auction id, calendar event id? data << uint32(mail->sender); // creature/gameobject entry, auction id, calendar event id?
break; break;
} }
// prevent client crash // prevent client crash
std::string subject = (*itr)->subject; std::string subject = mail->subject;
std::string body = (*itr)->body; std::string body = mail->body;
if (subject.find("| |") != std::string::npos) if (subject.find("| |") != std::string::npos)
{ {
@@ -646,20 +651,20 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
body = ""; body = "";
} }
data << uint32((*itr)->COD); // COD data << uint32(mail->COD); // COD
data << uint32(0); // probably changed in 3.3.3 data << uint32(0); // probably changed in 3.3.3
data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32(mail->stationery); // stationery (Stationery.dbc)
data << uint32((*itr)->money); // Gold data << uint32(mail->money); // Gold
data << uint32((*itr)->checked); // flags data << uint32(mail->checked); // flags
data << float(float((*itr)->expire_time - time(nullptr)) / DAY); // Time data << float(float(mail->expire_time - time(nullptr)) / DAY); // Time
data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) data << uint32(mail->mailTemplateId); // mail template (MailTemplate.dbc)
data << subject; // Subject string - once 00, when mail type = 3, max 256 data << subject; // Subject string - once 00, when mail type = 3, max 256
data << body; // message? max 8000 data << body; // message? max 8000
data << uint8(item_count); // client limit is 0x10 data << uint8(item_count); // client limit is 0x10
for (uint8 i = 0; i < item_count; ++i) for (uint8 i = 0; i < item_count; ++i)
{ {
Item* item = player->GetMItem((*itr)->items[i].item_guid); Item* item = player->GetMItem(mail->items[i].item_guid);
// item index (0-6?) // item index (0-6?)
data << uint8(i); data << uint8(i);
// item guid low? // item guid low?
@@ -688,11 +693,12 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
data << uint8(0); data << uint8(0);
} }
++realCount;
++mailsCount; ++mailsCount;
} }
data.put<uint32>(0, player->totalMailCount); // this will display warning about undelivered mail to player if realCount > mailsCount data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount
data.put<uint8>(4, uint8(mailsCount)); // set real send mails to client data.put<uint8>(4, mailsCount); // set real send mails to client
SendPacket(&data); SendPacket(&data);
// recalculate m_nextMailDelivereTime and unReadMails // recalculate m_nextMailDelivereTime and unReadMails
@@ -781,28 +787,27 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/)
uint32 count = 0; uint32 count = 0;
time_t now = time(nullptr); time_t now = time(nullptr);
std::set<uint32> sentSenders; std::set<uint32> sentSenders;
for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) for (Mail const* mail : _player->GetMails())
{ {
Mail* m = (*itr);
// must be not checked yet // must be not checked yet
if (m->checked & MAIL_CHECK_MASK_READ) if (mail->checked & MAIL_CHECK_MASK_READ)
continue; continue;
// and already delivered // and already delivered
if (now < m->deliver_time) if (now < mail->deliver_time)
continue; continue;
// only send each mail sender once // only send each mail sender once
if (sentSenders.count(m->sender)) if (sentSenders.count(mail->sender))
continue; continue;
data << (m->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(m->sender) : ObjectGuid::Empty); // player guid data << (mail->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(mail->sender) : ObjectGuid::Empty); // player guid
data << uint32(m->messageType != MAIL_NORMAL ? m->sender : 0); // non-player entries data << uint32(mail->messageType != MAIL_NORMAL ? mail->sender : 0); // non-player entries
data << uint32(m->messageType); data << uint32(mail->messageType);
data << uint32(m->stationery); data << uint32(mail->stationery);
data << float(m->deliver_time - now); data << float(mail->deliver_time - now);
sentSenders.insert(m->sender); sentSenders.insert(mail->sender);
++count; ++count;
if (count == 2) // do not display more than 2 mails if (count == 2) // do not display more than 2 mails
break; break;
+5 -3
View File
@@ -167,7 +167,7 @@ void MailDraft::SendReturnToSender(uint32 /*sender_acc*/, ObjectGuid::LowType se
SendMailTo(trans, MailReceiver(receiver, receiver_guid), MailSender(MAIL_NORMAL, sender_guid), MAIL_CHECK_MASK_RETURNED, 0); SendMailTo(trans, MailReceiver(receiver, receiver_guid), MailSender(MAIL_NORMAL, sender_guid), MAIL_CHECK_MASK_RETURNED, 0);
} }
void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay, uint32 custom_expiration, bool deleteMailItemsFromDB, bool sendMail) void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay, uint32 custom_expiration, bool deleteMailItemsFromDB, bool sendMail, int32 auctionId)
{ {
sScriptMgr->OnBeforeMailDraftSendMailTo(this, receiver, sender, checked, deliver_delay, custom_expiration, deleteMailItemsFromDB, sendMail); sScriptMgr->OnBeforeMailDraftSendMailTo(this, receiver, sender, checked, deliver_delay, custom_expiration, deleteMailItemsFromDB, sendMail);
@@ -221,11 +221,12 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
stmt->setString(++index, GetSubject()); stmt->setString(++index, GetSubject());
stmt->setString(++index, GetBody()); stmt->setString(++index, GetBody());
stmt->setBool (++index, !m_items.empty()); stmt->setBool (++index, !m_items.empty());
stmt->setUInt64(++index, uint64(expire_time)); stmt->setUInt32(++index, uint32(expire_time));
stmt->setUInt64(++index, uint64(deliver_time)); stmt->setUInt32(++index, uint32(deliver_time));
stmt->setUInt32(++index, m_money); stmt->setUInt32(++index, m_money);
stmt->setUInt32(++index, m_COD); stmt->setUInt32(++index, m_COD);
stmt->setUInt8 (++index, uint8(checked)); stmt->setUInt8 (++index, uint8(checked));
stmt->setInt32(++index, auctionId);
trans->Append(stmt); trans->Append(stmt);
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
@@ -267,6 +268,7 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
m->expire_time = expire_time; m->expire_time = expire_time;
m->deliver_time = deliver_time; m->deliver_time = deliver_time;
m->checked = checked; m->checked = checked;
m->auctionId = auctionId;
m->state = MAIL_STATE_UNCHANGED; m->state = MAIL_STATE_UNCHANGED;
pReceiver->AddMail(m); // to insert new mail to beginning of maillist pReceiver->AddMail(m); // to insert new mail to beginning of maillist
+5 -1
View File
@@ -127,7 +127,7 @@ public: // modifiers
public: // finishers public: // finishers
void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction trans); void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction trans);
void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0, uint32 custom_expiration = 0, bool deleteMailItemsFromDB = false, bool sendMail = true); void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked = MAIL_CHECK_MASK_NONE, uint32 deliver_delay = 0, uint32 custom_expiration = 0, bool deleteMailItemsFromDB = false, bool sendMail = true, int32 auctionId = 0);
private: private:
void deleteIncludedItems(CharacterDatabaseTransaction trans, bool inDB = false); void deleteIncludedItems(CharacterDatabaseTransaction trans, bool inDB = false);
@@ -170,6 +170,10 @@ struct Mail
uint32 checked; uint32 checked;
MailState state; MailState state;
// < 0 Pending
// > 0 Delivery
int32 auctionId;
void AddItem(ObjectGuid::LowType itemGuidLow, uint32 item_template) void AddItem(ObjectGuid::LowType itemGuidLow, uint32 item_template)
{ {
MailItemInfo mii; MailItemInfo mii;