mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-18 11:25:42 +00:00
fix(Core/Mail): cleanup pending auction sale mail (#6022)
This commit is contained in:
@@ -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_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_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_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_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_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);
|
||||
@@ -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_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_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_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);
|
||||
|
||||
@@ -135,7 +135,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabas
|
||||
}
|
||||
|
||||
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)
|
||||
.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)
|
||||
{
|
||||
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
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner.GetCounter()), auction, MAIL_CHECK_MASK_COPIED);
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING),
|
||||
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
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
.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 (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(auction->bidder.GetCounter()))
|
||||
@@ -222,7 +229,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, CharacterDat
|
||||
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
||||
|
||||
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)
|
||||
.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);
|
||||
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)
|
||||
.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();
|
||||
}
|
||||
|
||||
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;
|
||||
strm.width(16);
|
||||
strm << std::right << std::hex << guid.GetRawValue();
|
||||
strm << std::dec << ':' << bid << ':' << buyout;
|
||||
strm << ':' << deposit << ':' << cut;
|
||||
strm << ':' << moneyDelay << ':' << eta;
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ struct AuctionEntry
|
||||
void SaveToDB(CharacterDatabaseTransaction trans) const;
|
||||
bool LoadFromDB(Field* fields);
|
||||
[[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
|
||||
|
||||
@@ -847,7 +847,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
|
||||
m_mailsUpdated = false;
|
||||
unReadMails = 0;
|
||||
m_nextMailDelivereTime = 0;
|
||||
m_nextMailDelivereTime = time_t(0);
|
||||
|
||||
m_resetTalentsCost = 0;
|
||||
m_resetTalentsTime = 0;
|
||||
@@ -1605,7 +1605,7 @@ void Player::Update(uint32 p_time)
|
||||
++unReadMails;
|
||||
|
||||
// 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.
|
||||
@@ -3736,18 +3736,18 @@ void Player::UpdateNextMailTimeAndUnreads()
|
||||
//Get the next delivery time
|
||||
CharacterDatabasePreparedStatement* stmtNextDeliveryTime = CharacterDatabase.GetPreparedStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME);
|
||||
stmtNextDeliveryTime->setUInt32(0, GetGUID().GetCounter());
|
||||
stmtNextDeliveryTime->setUInt64(1, cTime);
|
||||
stmtNextDeliveryTime->setUInt32(1, uint32(cTime));
|
||||
PreparedQueryResult resultNextDeliveryTime = CharacterDatabase.Query(stmtNextDeliveryTime);
|
||||
if (resultNextDeliveryTime)
|
||||
{
|
||||
Field* fields = resultNextDeliveryTime->Fetch();
|
||||
m_nextMailDelivereTime = fields[0].GetUInt64();
|
||||
m_nextMailDelivereTime = time_t(fields[0].GetUInt32());
|
||||
}
|
||||
|
||||
//Get unread mails count
|
||||
CharacterDatabasePreparedStatement* stmtUnreadAmount = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH);
|
||||
stmtUnreadAmount->setUInt32(0, GetGUID().GetCounter());
|
||||
stmtUnreadAmount->setUInt64(1, cTime);
|
||||
stmtUnreadAmount->setUInt32(1, uint32(cTime));
|
||||
PreparedQueryResult resultUnreadAmount = CharacterDatabase.Query(stmtUnreadAmount);
|
||||
if (resultUnreadAmount)
|
||||
{
|
||||
@@ -19148,13 +19148,13 @@ void Player::_LoadMail()
|
||||
}
|
||||
|
||||
//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;
|
||||
m_mailCache.erase(itr);
|
||||
if(m)
|
||||
delete m;
|
||||
itr = GetMailBegin();
|
||||
Mail* mail = *itr;
|
||||
itr = m_mailCache.erase(itr);
|
||||
|
||||
if (mail)
|
||||
delete mail;
|
||||
}
|
||||
|
||||
// Delete mailed items aswell
|
||||
@@ -19162,13 +19162,19 @@ void Player::_LoadMail()
|
||||
for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
std::set<uint32> pendingAuctions;
|
||||
std::unordered_map<uint32, Mail*> pendingAuctionMails;
|
||||
|
||||
mMitems.clear();
|
||||
|
||||
//Now load the new ones
|
||||
m_mailCache.clear();
|
||||
|
||||
CharacterDatabaseTransaction pendingAuctionsTrans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
|
||||
stmt->setUInt32(0, GetGUID().GetCounter());
|
||||
stmt->setUInt64(1, time(nullptr));
|
||||
stmt->setUInt32(1, uint32(time(nullptr)));
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
if (result)
|
||||
{
|
||||
@@ -19192,6 +19198,7 @@ void Player::_LoadMail()
|
||||
m->checked = fields[11].GetUInt8();
|
||||
m->stationery = fields[12].GetUInt8();
|
||||
m->mailTemplateId = fields[13].GetInt16();
|
||||
m->auctionId = fields[14].GetInt32();
|
||||
|
||||
if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId))
|
||||
{
|
||||
@@ -19204,10 +19211,60 @@ void Player::_LoadMail()
|
||||
if (has_items)
|
||||
_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);
|
||||
}
|
||||
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()
|
||||
|
||||
@@ -1653,8 +1653,7 @@ public:
|
||||
uint32 GetMailCacheSize() { return m_mailCache.size();}
|
||||
Mail* GetMail(uint32 id);
|
||||
|
||||
PlayerMails::iterator GetMailBegin() { return m_mailCache.begin();}
|
||||
PlayerMails::iterator GetMailEnd() { return m_mailCache.end();}
|
||||
PlayerMails const& GetMails() const { return m_mailCache; }
|
||||
|
||||
/*********************************************************/
|
||||
/*** MAILED ITEMS SYSTEM ***/
|
||||
|
||||
@@ -5681,14 +5681,14 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
|
||||
time_t curTime = time(nullptr);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL);
|
||||
stmt->setUInt32(0, curTime);
|
||||
stmt->setUInt32(0, uint32(curTime));
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
std::map<uint32 /*messageId*/, MailItemInfoVec> itemsCache;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS);
|
||||
stmt->setUInt32(0, curTime);
|
||||
stmt->setUInt32(0, uint32(curTime));
|
||||
if (PreparedQueryResult items = CharacterDatabase.Query(stmt))
|
||||
{
|
||||
MailItemInfo item;
|
||||
@@ -5714,10 +5714,11 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
|
||||
m->receiver = fields[3].GetUInt32();
|
||||
bool has_items = fields[4].GetBool();
|
||||
m->expire_time = time_t(fields[5].GetUInt32());
|
||||
m->deliver_time = 0;
|
||||
m->deliver_time = time_t(0);
|
||||
m->COD = fields[6].GetUInt32();
|
||||
m->checked = fields[7].GetUInt8();
|
||||
m->mailTemplateId = fields[8].GetInt16();
|
||||
m->auctionId = fields[9].GetInt32();
|
||||
|
||||
Player* player = nullptr;
|
||||
if (serverUp)
|
||||
@@ -5755,8 +5756,8 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL_RETURNED);
|
||||
stmt->setUInt32(0, m->receiver);
|
||||
stmt->setUInt32(1, m->sender);
|
||||
stmt->setUInt32(2, curTime + 30 * DAY);
|
||||
stmt->setUInt32(3, curTime);
|
||||
stmt->setUInt32(2, uint32(curTime + 30 * DAY));
|
||||
stmt->setUInt32(3, uint32(curTime));
|
||||
stmt->setUInt8 (4, uint8(MAIL_CHECK_MASK_RETURNED));
|
||||
stmt->setUInt32(5, m->messageID);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
@@ -550,7 +550,7 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
// 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)
|
||||
.SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
|
||||
@@ -113,12 +113,12 @@ bool LoginQueryHolder::Initialize()
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT);
|
||||
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);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD);
|
||||
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);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE);
|
||||
|
||||
@@ -588,54 +588,59 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
|
||||
Player* player = _player;
|
||||
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
|
||||
data << uint32(0); // real mail's count
|
||||
data << uint8(0); // mail's count
|
||||
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
|
||||
if (mailsCount >= MAX_INBOX_CLIENT_CAPACITY)
|
||||
{
|
||||
break;
|
||||
++realCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip deleted or not delivered (deliver delay not expired) mails
|
||||
if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->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)
|
||||
if (mail->state == MAIL_STATE_DELETED || cur_time < mail->deliver_time)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
data << uint16(next_mail_size); // Message size
|
||||
data << uint32((*itr)->messageID); // Message ID
|
||||
data << uint8((*itr)->messageType); // Message Type
|
||||
uint8 item_count = uint8(mail->items.size()); // max count is MAX_MAIL_ITEMS (12)
|
||||
|
||||
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
|
||||
data << ObjectGuid::Create<HighGuid::Player>((*itr)->sender);
|
||||
data << ObjectGuid::Create<HighGuid::Player>(mail->sender);
|
||||
break;
|
||||
case MAIL_CREATURE:
|
||||
case MAIL_GAMEOBJECT:
|
||||
case MAIL_AUCTION:
|
||||
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;
|
||||
}
|
||||
|
||||
// prevent client crash
|
||||
std::string subject = (*itr)->subject;
|
||||
std::string body = (*itr)->body;
|
||||
std::string subject = mail->subject;
|
||||
std::string body = mail->body;
|
||||
|
||||
if (subject.find("| |") != std::string::npos)
|
||||
{
|
||||
@@ -646,20 +651,20 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
|
||||
body = "";
|
||||
}
|
||||
|
||||
data << uint32((*itr)->COD); // COD
|
||||
data << uint32(0); // probably changed in 3.3.3
|
||||
data << uint32((*itr)->stationery); // stationery (Stationery.dbc)
|
||||
data << uint32((*itr)->money); // Gold
|
||||
data << uint32((*itr)->checked); // flags
|
||||
data << float(float((*itr)->expire_time - time(nullptr)) / DAY); // Time
|
||||
data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc)
|
||||
data << subject; // Subject string - once 00, when mail type = 3, max 256
|
||||
data << body; // message? max 8000
|
||||
data << uint8(item_count); // client limit is 0x10
|
||||
data << uint32(mail->COD); // COD
|
||||
data << uint32(0); // probably changed in 3.3.3
|
||||
data << uint32(mail->stationery); // stationery (Stationery.dbc)
|
||||
data << uint32(mail->money); // Gold
|
||||
data << uint32(mail->checked); // flags
|
||||
data << float(float(mail->expire_time - time(nullptr)) / DAY); // Time
|
||||
data << uint32(mail->mailTemplateId); // mail template (MailTemplate.dbc)
|
||||
data << subject; // Subject string - once 00, when mail type = 3, max 256
|
||||
data << body; // message? max 8000
|
||||
data << uint8(item_count); // client limit is 0x10
|
||||
|
||||
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?)
|
||||
data << uint8(i);
|
||||
// item guid low?
|
||||
@@ -688,11 +693,12 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
|
||||
data << uint8(0);
|
||||
}
|
||||
|
||||
++realCount;
|
||||
++mailsCount;
|
||||
}
|
||||
|
||||
data.put<uint32>(0, player->totalMailCount); // 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<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount
|
||||
data.put<uint8>(4, mailsCount); // set real send mails to client
|
||||
SendPacket(&data);
|
||||
|
||||
// recalculate m_nextMailDelivereTime and unReadMails
|
||||
@@ -781,28 +787,27 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/)
|
||||
uint32 count = 0;
|
||||
time_t now = time(nullptr);
|
||||
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
|
||||
if (m->checked & MAIL_CHECK_MASK_READ)
|
||||
if (mail->checked & MAIL_CHECK_MASK_READ)
|
||||
continue;
|
||||
|
||||
// and already delivered
|
||||
if (now < m->deliver_time)
|
||||
if (now < mail->deliver_time)
|
||||
continue;
|
||||
|
||||
// only send each mail sender once
|
||||
if (sentSenders.count(m->sender))
|
||||
if (sentSenders.count(mail->sender))
|
||||
continue;
|
||||
|
||||
data << (m->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(m->sender) : ObjectGuid::Empty); // player guid
|
||||
data << uint32(m->messageType != MAIL_NORMAL ? m->sender : 0); // non-player entries
|
||||
data << uint32(m->messageType);
|
||||
data << uint32(m->stationery);
|
||||
data << float(m->deliver_time - now);
|
||||
data << (mail->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(mail->sender) : ObjectGuid::Empty); // player guid
|
||||
data << uint32(mail->messageType != MAIL_NORMAL ? mail->sender : 0); // non-player entries
|
||||
data << uint32(mail->messageType);
|
||||
data << uint32(mail->stationery);
|
||||
data << float(mail->deliver_time - now);
|
||||
|
||||
sentSenders.insert(m->sender);
|
||||
sentSenders.insert(mail->sender);
|
||||
++count;
|
||||
if (count == 2) // do not display more than 2 mails
|
||||
break;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -221,11 +221,12 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
stmt->setString(++index, GetSubject());
|
||||
stmt->setString(++index, GetBody());
|
||||
stmt->setBool (++index, !m_items.empty());
|
||||
stmt->setUInt64(++index, uint64(expire_time));
|
||||
stmt->setUInt64(++index, uint64(deliver_time));
|
||||
stmt->setUInt32(++index, uint32(expire_time));
|
||||
stmt->setUInt32(++index, uint32(deliver_time));
|
||||
stmt->setUInt32(++index, m_money);
|
||||
stmt->setUInt32(++index, m_COD);
|
||||
stmt->setUInt8 (++index, uint8(checked));
|
||||
stmt->setInt32(++index, auctionId);
|
||||
trans->Append(stmt);
|
||||
|
||||
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->deliver_time = deliver_time;
|
||||
m->checked = checked;
|
||||
m->auctionId = auctionId;
|
||||
m->state = MAIL_STATE_UNCHANGED;
|
||||
|
||||
pReceiver->AddMail(m); // to insert new mail to beginning of maillist
|
||||
|
||||
@@ -127,7 +127,7 @@ public: // modifiers
|
||||
|
||||
public: // finishers
|
||||
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:
|
||||
void deleteIncludedItems(CharacterDatabaseTransaction trans, bool inDB = false);
|
||||
@@ -170,6 +170,10 @@ struct Mail
|
||||
uint32 checked;
|
||||
MailState state;
|
||||
|
||||
// < 0 Pending
|
||||
// > 0 Delivery
|
||||
int32 auctionId;
|
||||
|
||||
void AddItem(ObjectGuid::LowType itemGuidLow, uint32 item_template)
|
||||
{
|
||||
MailItemInfo mii;
|
||||
|
||||
Reference in New Issue
Block a user