diff --git a/src/common/Database/Implementation/CharacterDatabase.cpp b/src/common/Database/Implementation/CharacterDatabase.cpp index 04a310b7c..4fed23ba1 100644 --- a/src/common/Database/Implementation/CharacterDatabase.cpp +++ b/src/common/Database/Implementation/CharacterDatabase.cpp @@ -78,7 +78,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND deliver_time <= ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); @@ -398,8 +400,8 @@ 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 = ? ORDER BY id DESC", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAIL_ASYNCH, "SELECT ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyId, ii.durability, ii.playedTime, ii.text, mi.item_guid, ii.itemEntry, ii.owner_guid, mail.id, mail.messageType, mail.sender, mail.receiver, mail.subject, mail.body, mail.has_items, mail.expire_time, mail.deliver_time, mail.money, mail.cod, mail.checked, mail.stationery, mail.mailTemplateId FROM mail LEFT JOIN (mail_items mi JOIN item_instance ii) ON (mi.mail_id = mail.id AND mi.item_guid = ii.guid) WHERE mail.receiver = ? ORDER BY mail.id DESC", CONNECTION_ASYNC); + 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_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); 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/common/Database/Implementation/CharacterDatabase.h b/src/common/Database/Implementation/CharacterDatabase.h index 548f07bad..97da2293f 100644 --- a/src/common/Database/Implementation/CharacterDatabase.h +++ b/src/common/Database/Implementation/CharacterDatabase.h @@ -83,6 +83,8 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_ACTIONS, CHAR_SEL_CHARACTER_ACTIONS_SPEC, CHAR_SEL_CHARACTER_MAILCOUNT, + CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD, + CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH, CHAR_SEL_CHARACTER_MAILDATE, CHAR_SEL_CHARACTER_SOCIALLIST, CHAR_SEL_CHARACTER_HOMEBIND, @@ -345,7 +347,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHAR_OLD_CHARS, CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, CHAR_SEL_MAIL, - CHAR_SEL_MAIL_ASYNCH, + CHAR_SEL_NEXT_MAIL_DELIVERYTIME, CHAR_DEL_CHAR_AURA_FROZEN, CHAR_SEL_CHAR_INVENTORY_COUNT_ITEM, CHAR_SEL_MAIL_COUNT_ITEM, diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 70402b0ac..80baf23e0 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -826,7 +826,6 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) _restBonus = 0; ////////////////////Rest System///////////////////// - m_mailsLoaded = false; m_mailsUpdated = false; unReadMails = 0; m_nextMailDelivereTime = 0; @@ -980,8 +979,10 @@ Player::~Player() delete itr->second; //all mailed items should be deleted, also all mail should be deallocated - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end(); ++itr) + { delete *itr; + } for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated @@ -3631,12 +3632,12 @@ void Player::SendInitialSpells() void Player::RemoveMail(uint32 id) { - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end(); ++itr) { if ((*itr)->messageID == id) { //do not delete item, because Player::removeMail() is called when returning mail to sender. - m_mail.erase(itr); + m_mailCache.erase(itr); return; } } @@ -3668,26 +3669,36 @@ void Player::SendNewMail() void Player::UpdateNextMailTimeAndUnreads() { - // calculate next delivery time (min. from non-delivered mails - // and recalculate unReadMail + //Update the next delivery time and unread mails time_t cTime = time(nullptr); - m_nextMailDelivereTime = 0; - unReadMails = 0; - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + //Get the next delivery time + PreparedStatement* stmtNextDeliveryTime = CharacterDatabase.GetPreparedStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME); + stmtNextDeliveryTime->setUInt64(0, GetGUIDLow()); + stmtNextDeliveryTime->setUInt64(1, cTime); + PreparedQueryResult resultNextDeliveryTime = CharacterDatabase.Query(stmtNextDeliveryTime); + if (resultNextDeliveryTime) { - if ((*itr)->deliver_time > cTime) - { - if (!m_nextMailDelivereTime || m_nextMailDelivereTime > (*itr)->deliver_time) - m_nextMailDelivereTime = (*itr)->deliver_time; - } - else if (((*itr)->checked & MAIL_CHECK_MASK_READ) == 0) - ++unReadMails; + Field* fields = resultNextDeliveryTime->Fetch(); + m_nextMailDelivereTime = fields[0].GetUInt64(); + } + + //Get unread mails count + PreparedStatement* stmtUnreadAmount = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH); + stmtUnreadAmount->setUInt64(0, GetGUIDLow()); + stmtUnreadAmount->setUInt64(1, cTime); + PreparedQueryResult resultUnreadAmount = CharacterDatabase.Query(stmtUnreadAmount); + if (resultUnreadAmount) + { + Field* fields = resultUnreadAmount->Fetch(); + unReadMails = uint8(fields[0].GetUInt64()); } } void Player::AddNewMailDeliverTime(time_t deliver_time) { - if (deliver_time <= time(nullptr)) // ready now + ++totalMailCount; + sWorld->UpdateGlobalPlayerMails(GetGUIDLow(), totalMailCount, false); + if (deliver_time <= time(nullptr)) // ready now { ++unReadMails; SendNewMail(); @@ -4600,10 +4611,13 @@ void Player::SetFreeTalentPoints(uint32 points) Mail* Player::GetMail(uint32 id) { - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end(); ++itr) + { if ((*itr)->messageID == id) + { return (*itr); - + } + } return nullptr; } @@ -18357,10 +18371,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder* holder) // xinef: load mails before inventory, so problematic items can be added to already loaded mails // unread mails and next delivery time, actual mails not loaded - _LoadMailInit(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE)); - - // pussywizard: - _LoadMailAsynch(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL)); + _LoadMailInit(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_UNREAD_COUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE)); _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), time_diff); @@ -19049,8 +19060,15 @@ void Player::_LoadMailedItems(Mail* mail) } while (result->NextRow()); } -void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery) +void Player::_LoadMailInit(PreparedQueryResult resultMailCount, PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery) { + //Set count for all mails used to display correct size later one + if (resultMailCount) + { + totalMailCount = uint64((*resultMailCount)[0].GetUInt64()); + sWorld->UpdateGlobalPlayerMails(GetGUIDLow(), totalMailCount, false); + } + //set a count of unread mails //QueryResult* resultMails = CharacterDatabase.PQuery("SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(playerGuid), (uint64)cTime); if (resultUnread) @@ -19062,130 +19080,60 @@ void Player::_LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult m_nextMailDelivereTime = time_t((*resultDelivery)[0].GetUInt32()); } -void Player::_LoadMailAsynch(PreparedQueryResult result) -{ - m_mail.clear(); - uint32 prevMailID = 0; - Mail* m = nullptr; - if (result) - { - do - { - Field* fields = result->Fetch(); - if (fields[14].GetUInt32() != prevMailID) - { - if (m) - m_mail.push_back(m); - - m = new Mail; - - m->messageID = fields[14].GetUInt32(); - m->messageType = fields[15].GetUInt8(); - m->sender = fields[16].GetUInt32(); - m->receiver = fields[17].GetUInt32(); - m->subject = fields[18].GetString(); - m->body = fields[19].GetString(); - // has_items = fields[20].GetBool(); - m->expire_time = time_t(fields[21].GetUInt32()); - m->deliver_time = time_t(fields[22].GetUInt32()); - m->money = fields[23].GetUInt32(); - m->COD = fields[24].GetUInt32(); - m->checked = fields[25].GetUInt8(); - m->stationery = fields[26].GetUInt8(); - m->mailTemplateId = fields[27].GetInt16(); - - if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) - { - sLog->outError("Player::_LoadMail - Mail (%u) have not existed MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); - m->mailTemplateId = 0; - } - - m->state = MAIL_STATE_UNCHANGED; - } - - if (m && fields[20].GetBool() /*has_items*/ && fields[12].GetUInt32() /*itemEntry*/) - { - uint32 itemGuid = fields[11].GetUInt32(); - uint32 itemTemplate = fields[12].GetUInt32(); - - m->AddItem(itemGuid, itemTemplate); - - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTemplate); - - if (!proto) - { - sLog->outError("Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), itemGuid, itemTemplate, m->messageID); - - PreparedStatement* 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, MAKE_NEW_GUID(fields[13].GetUInt32(), 0, HIGHGUID_PLAYER), fields, itemTemplate)) - { - sLog->outError("Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", m->messageID, itemGuid); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); - stmt->setUInt32(0, itemGuid); - CharacterDatabase.Execute(stmt); - - item->FSetState(ITEM_REMOVED); - - SQLTransaction temp = SQLTransaction(nullptr); - item->SaveToDB(temp); // it also deletes item object ! - continue; - } - - AddMItem(item); - } - - prevMailID = fields[14].GetUInt32(); - } while (result->NextRow()); - - m_mail.push_back(m); - } - // Xinef: this is stored during storage initialization - sWorld->UpdateGlobalPlayerMails(GetGUIDLow(), m_mail.size(), false); - m_mailsLoaded = true; -} - void Player::_LoadMail() { - m_mail.clear(); + //In case we are not expecting to receive new mail we just exits, not really necessary to refresh any data + if (m_nextMailDelivereTime > time(nullptr)) + { + return; + } + if (m_mailsUpdated) + { + //Save changed data to the sql before refreshing so we always get up to date data + SQLTransaction saveTransaction = CharacterDatabase.BeginTransaction(); + _SaveMail(saveTransaction); + CharacterDatabase.CommitTransaction(saveTransaction); + } + + //This should in theory always be < 100 + for (PlayerMails::iterator itr = GetMailBegin(); itr != GetMailEnd(); ++itr) + { + delete *itr; + m_mailCache.erase(itr); + itr = GetMailBegin(); + } + + //Now load the new ones + m_mailCache.clear(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL); stmt->setUInt32(0, GetGUIDLow()); + stmt->setUInt64(1, time(nullptr)); PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (result) { do { Field* fields = result->Fetch(); + Mail* m = new Mail; - m->messageID = fields[0].GetUInt32(); - m->messageType = fields[1].GetUInt8(); - m->sender = fields[2].GetUInt32(); - 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->messageID = fields[0].GetUInt32(); + m->messageType = fields[1].GetUInt8(); + m->sender = fields[2].GetUInt32(); + 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(); + if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) { sLog->outError("Player::_LoadMail - Mail (%u) have not existed MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); @@ -19197,10 +19145,10 @@ void Player::_LoadMail() if (has_items) _LoadMailedItems(m); - m_mail.push_back(m); - } while (result->NextRow()); + m_mailCache.push_back(m); + } + while (result->NextRow()); } - m_mailsLoaded = true; } void Player::LoadPet() @@ -20092,12 +20040,14 @@ void Player::_SaveInventory(SQLTransaction& trans) void Player::_SaveMail(SQLTransaction& trans) { - if (!m_mailsLoaded) + if (!GetMailCacheSize() || !m_mailsUpdated) + { return; + } PreparedStatement* stmt = nullptr; - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) + for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end(); ++itr) { Mail* m = (*itr); if (m->state == MAIL_STATE_CHANGED) @@ -20147,14 +20097,14 @@ void Player::_SaveMail(SQLTransaction& trans) } //deallocate deleted mails... - for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();) + for (PlayerMails::iterator itr = m_mailCache.begin(); itr != m_mailCache.end();) { if ((*itr)->state == MAIL_STATE_DELETED) { Mail* m = *itr; - m_mail.erase(itr); + m_mailCache.erase(itr); delete m; - itr = m_mail.begin(); + itr = m_mailCache.begin(); } else ++itr; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f2982fc09..cf53bcbb6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -820,11 +820,12 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_INVENTORY = 8, PLAYER_LOGIN_QUERY_LOAD_ACTIONS = 9, PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT = 10, - PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE = 11, - PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 12, - PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 13, - PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 14, - PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 15, + PLAYER_LOGIN_QUERY_LOAD_MAIL_UNREAD_COUNT = 11, + PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE = 12, + PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 13, + PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 14, + PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 15, + PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 16, PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS = 18, PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS = 19, PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS = 20, @@ -840,7 +841,6 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30, PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31, PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32, - PLAYER_LOGIN_QUERY_LOAD_MAIL = 33, PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH = 34, MAX_PLAYER_LOGIN_QUERY, }; @@ -1611,7 +1611,6 @@ public: static void DeleteOldCharacters(); static void DeleteOldCharacters(uint32 keepDays); - bool m_mailsLoaded; bool m_mailsUpdated; void SetBindPoint(uint64 guid); @@ -1667,22 +1666,23 @@ public: void SendNewMail(); void UpdateNextMailTimeAndUnreads(); void AddNewMailDeliverTime(time_t deliver_time); - bool IsMailsLoaded() const { return m_mailsLoaded; } void RemoveMail(uint32 id); - void AddMail(Mail* mail) { m_mail.push_front(mail);}// for call from WorldSession::SendMailTo - uint32 GetMailSize() { return m_mail.size();} + void AddMail(Mail* mail) { m_mailCache.push_front(mail); }// for call from WorldSession::SendMailTo + uint32 GetMailSize() { return totalMailCount; } + uint32 GetMailCacheSize() { return m_mailCache.size();} Mail* GetMail(uint32 id); - PlayerMails::iterator GetMailBegin() { return m_mail.begin();} - PlayerMails::iterator GetMailEnd() { return m_mail.end();} + PlayerMails::iterator GetMailBegin() { return m_mailCache.begin();} + PlayerMails::iterator GetMailEnd() { return m_mailCache.end();} /*********************************************************/ /*** MAILED ITEMS SYSTEM ***/ /*********************************************************/ uint8 unReadMails; + uint64 totalMailCount; time_t m_nextMailDelivereTime; typedef std::unordered_map ItemMap; @@ -2728,8 +2728,7 @@ protected: void _LoadAuras(PreparedQueryResult result, uint32 timediff); void _LoadGlyphAuras(); void _LoadInventory(PreparedQueryResult result, uint32 timeDiff); - void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); - void _LoadMailAsynch(PreparedQueryResult result); + void _LoadMailInit(PreparedQueryResult resultMailCount, PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); void _LoadMailedItems(Mail* mail); void _LoadQuestStatus(PreparedQueryResult result); @@ -2828,7 +2827,7 @@ protected: uint32 m_GuildIdInvited; uint32 m_ArenaTeamIdInvited; - PlayerMails m_mail; + PlayerMails m_mailCache; PlayerSpellMap m_spells; PlayerTalentMap m_talents; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 038f02650..484ca222b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -112,6 +112,11 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(1, uint64(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(NULL))); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_UNREAD_COUNT, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE); stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE, stmt); @@ -179,10 +184,6 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW, stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_ASYNCH); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL, stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BREW_OF_THE_MONTH); stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH, stmt); diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index c6603b1df..c3206c130 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -584,13 +584,9 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) return; Player* player = _player; + player->_LoadMail(); - //load players mails, and mailed items - if (!player->m_mailsLoaded) - player->_LoadMail(); - - uint32 mailsCount = 0; // real send to client mails amount - uint32 realCount = 0; // real mails amount + uint32 mailsCount = 0; // real send to client mails amount // real mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint32(0); // real mail's count @@ -602,8 +598,7 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) // prevent client storage overflow if (mailsCount >= MAX_INBOX_CLIENT_CAPACITY) { - realCount += 1; - continue; + break; } // skip deleted or not delivered (deliver delay not expired) mails @@ -616,7 +611,6 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) if (data.wpos() + next_mail_size > MAX_NETCLIENT_PACKET_SIZE) { - realCount += 1; continue; } @@ -692,11 +686,10 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) data << uint8(0); } - ++realCount; ++mailsCount; } - data.put(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount + data.put(0, player->totalMailCount); // this will display warning about undelivered mail to player if realCount > mailsCount data.put(4, uint8(mailsCount)); // set real send mails to client SendPacket(&data); @@ -778,8 +771,7 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/) { WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); - if (!_player->m_mailsLoaded) - _player->_LoadMail(); + _player->_LoadMail(); if (_player->unReadMails > 0) { diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp index 151928594..d4c949ac5 100644 --- a/src/server/game/Mails/Mail.cpp +++ b/src/server/game/Mails/Mail.cpp @@ -246,43 +246,37 @@ void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, { pReceiver->AddNewMailDeliverTime(deliver_time); - if (pReceiver->IsMailsLoaded()) + Mail* m = new Mail; + m->messageID = mailId; + m->mailTemplateId = GetMailTemplateId(); + m->subject = GetSubject(); + m->body = GetBody(); + m->money = GetMoney(); + m->COD = GetCOD(); + + for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { - Mail* m = new Mail; - m->messageID = mailId; - m->mailTemplateId = GetMailTemplateId(); - m->subject = GetSubject(); - m->body = GetBody(); - m->money = GetMoney(); - m->COD = GetCOD(); - - for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) - { - Item* item = mailItemIter->second; - m->AddItem(item->GetGUIDLow(), item->GetEntry()); - } - - m->messageType = sender.GetMailMessageType(); - m->stationery = sender.GetStationery(); - m->sender = sender.GetSenderId(); - m->receiver = receiver.GetPlayerGUIDLow(); - m->expire_time = expire_time; - m->deliver_time = deliver_time; - m->checked = checked; - m->state = MAIL_STATE_UNCHANGED; - - pReceiver->AddMail(m); // to insert new mail to beginning of maillist - - if (!m_items.empty()) - { - for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) - pReceiver->AddMItem(mailItemIter->second); - } + Item* item = mailItemIter->second; + m->AddItem(item->GetGUIDLow(), item->GetEntry()); } - else if (!m_items.empty()) + + m->messageType = sender.GetMailMessageType(); + m->stationery = sender.GetStationery(); + m->sender = sender.GetSenderId(); + m->receiver = receiver.GetPlayerGUIDLow(); + m->expire_time = expire_time; + m->deliver_time = deliver_time; + m->checked = checked; + m->state = MAIL_STATE_UNCHANGED; + + pReceiver->AddMail(m); // to insert new mail to beginning of maillist + + if (!m_items.empty()) { - SQLTransaction temp = SQLTransaction(nullptr); - deleteIncludedItems(temp); + for (MailItemMap::iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) + { + pReceiver->AddMItem(mailItemIter->second); + } } } else if (!m_items.empty())