diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 27 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/MailHandler.cpp | 382 | ||||
-rw-r--r-- | src/server/game/Handlers/NPCHandler.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Server/Packets/AllPackets.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MailPackets.cpp | 300 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MailPackets.h | 269 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 40 |
8 files changed, 729 insertions, 300 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 850f7aa554a..d9ee88f9499 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -62,6 +62,7 @@ #include "LootItemStorage.h" #include "LootMgr.h" #include "Mail.h" +#include "MailPackets.h" #include "MapManager.h" #include "MiscPackets.h" #include "MotionMaster.h" @@ -2992,26 +2993,22 @@ void Player::RemoveMail(uint32 id) void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, ObjectGuid::LowType item_guid, uint32 item_count) const { - WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(4+4))); - data << (uint32) mailId; - data << (uint32) mailAction; - data << (uint32) mailError; - if (mailError == MAIL_ERR_EQUIP_ERROR) - data << (uint32) equipError; - else if (mailAction == MAIL_ITEM_TAKEN) - { - data << (uint32) item_guid; // item guid low? - data << (uint32) item_count; // item count? - } - SendDirectMessage(&data); + WorldPackets::Mail::MailCommandResult result; + result.MailID = mailId; + result.Command = mailAction; + result.ErrorCode = mailError; + result.BagResult = equipError; + result.AttachID = item_guid; + result.QtyInInventory = item_count; + SendDirectMessage(result.Write()); } void Player::SendNewMail() const { // deliver undelivered mail - WorldPacket data(SMSG_RECEIVED_MAIL, 4); - data << (uint32) 0; - SendDirectMessage(&data); + WorldPackets::Mail::NotifyReceivedMail notify; + notify.Delay = 0.0f; + SendDirectMessage(notify.Write()); } void Player::UpdateNextMailTimeAndUnreads() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 97c1826b9c0..a802f6ca271 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1386,8 +1386,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 GetMailSize() { return m_mail.size();} Mail* GetMail(uint32 id); - PlayerMails::iterator GetMailBegin() { return m_mail.begin();} - PlayerMails::iterator GetMailEnd() { return m_mail.end();} + PlayerMails const& GetMails() const { return m_mail; } void SendItemRetrievalMail(uint32 itemEntry, uint32 count); // Item retrieval mails sent by The Postmaster (34337), used in multiple places. diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index cca8f2b0c67..4d97191cecc 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -25,6 +25,7 @@ #include "Language.h" #include "Log.h" #include "Mail.h" +#include "MailPackets.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -58,74 +59,56 @@ bool WorldSession::CanOpenMailBox(ObjectGuid guid) return true; } -void WorldSession::HandleSendMail(WorldPacket& recvData) +void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& sendMail) { - ObjectGuid mailbox, unk3; - std::string receiverName, subject, body; - uint32 stationery, package, money, COD; - uint8 unk4; - uint8 items_count; - recvData >> mailbox >> receiverName >> subject >> body - >> stationery // stationery? - >> package // 0x00000000 - >> items_count; // attached items count - - if (items_count > MAX_MAIL_ITEMS) // client limit - { - GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); - recvData.rfinish(); // set to end to avoid warnings spam + if (!CanOpenMailBox(sendMail.Info.Mailbox)) return; - } - - ObjectGuid itemGUIDs[MAX_MAIL_ITEMS]; - - for (uint8 i = 0; i < items_count; ++i) - { - recvData.read_skip<uint8>(); // item slot in mail, not used - recvData >> itemGUIDs[i]; - } - - recvData >> money >> COD; // money and cod - recvData >> unk3; // const 0 - recvData >> unk4; // const 0 - - // packet read complete, now do check - if (!CanOpenMailBox(mailbox)) - return; - - if (receiverName.empty()) - return; - - if (!ValidateHyperlinksAndMaybeKick(subject) || !ValidateHyperlinksAndMaybeKick(body)) + if (sendMail.Info.Target.empty()) return; Player* player = _player; - if (player->GetLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) + if (_player->GetLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } ObjectGuid receiverGuid; - if (normalizePlayerName(receiverName)) - receiverGuid = sCharacterCache->GetCharacterGuidByName(receiverName); + if (normalizePlayerName(sendMail.Info.Target)) + receiverGuid = sCharacterCache->GetCharacterGuidByName(sendMail.Info.Target); if (!receiverGuid) { TC_LOG_INFO("network", "Player %s is sending mail to %s (GUID: non-existing!) with subject %s " - "and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", - player->GetGUID().ToString().c_str(), receiverName.c_str(), subject.c_str(), body.c_str(), - items_count, money, COD, stationery, package); + "and body %s includes " SZFMTD " items, %u copper and %u COD copper with StationeryID = %d, PackageID = %d", + GetPlayerInfo().c_str(), sendMail.Info.Target.c_str(), sendMail.Info.Subject.c_str(), sendMail.Info.Body.c_str(), + sendMail.Info.Attachments.size(), sendMail.Info.SendMoney, sendMail.Info.Cod, sendMail.Info.StationeryID, sendMail.Info.PackageID); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } + if (sendMail.Info.SendMoney < 0) + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); + TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative money value (SendMoney: %d)", + GetPlayerInfo().c_str(), sendMail.Info.Target.c_str(), receiverGuid.ToString().c_str(), sendMail.Info.SendMoney); + return; + } + + if (sendMail.Info.Cod < 0) + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); + TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative COD value (Cod: %d)", + GetPlayerInfo().c_str(), sendMail.Info.Target.c_str(), receiverGuid.ToString().c_str(), sendMail.Info.Cod); + return; + } + TC_LOG_INFO("network", "Player %s is sending mail to %s (%s) with subject %s and body %s " - "including %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", - player->GetGUID().ToString().c_str(), receiverName.c_str(), receiverGuid.ToString().c_str(), subject.c_str(), - body.c_str(), items_count, money, COD, stationery, package); + "including " SZFMTD " items, %u copper and %u COD copper with StationeryID = %d, PackageID = %d", + GetPlayerInfo().c_str(), sendMail.Info.Target.c_str(), receiverGuid.ToString().c_str(), sendMail.Info.Subject.c_str(), + sendMail.Info.Body.c_str(), sendMail.Info.Attachments.size(), sendMail.Info.SendMoney, sendMail.Info.Cod, sendMail.Info.StationeryID, sendMail.Info.PackageID); if (player->GetGUID() == receiverGuid) { @@ -133,12 +116,12 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client + int32 cost = !sendMail.Info.Attachments.empty() ? 30 * sendMail.Info.Attachments.size() : 30; // price hardcoded in client - uint32 reqmoney = cost + money; + int32 reqmoney = cost + sendMail.Info.SendMoney; // Check for overflow - if (reqmoney < money) + if (reqmoney < sendMail.Info.SendMoney) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; @@ -192,10 +175,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } // test the receiver's Faction... or all items are account bound - bool accountBound = items_count ? true : false; - for (uint8 i = 0; i < items_count; ++i) + bool accountBound = !sendMail.Info.Attachments.empty(); + for (auto const& att : sendMail.Info.Attachments) { - if (Item* item = player->GetItemByGuid(itemGUIDs[i])) + if (Item* item = player->GetItemByGuid(att.ItemGUID)) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !itemProto->HasFlag(ITEM_FLAG_IS_BOUND_TO_ACCOUNT)) @@ -218,17 +201,17 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - Item* items[MAX_MAIL_ITEMS]; + std::vector<Item*> items; - for (uint8 i = 0; i < items_count; ++i) + for (auto const& att : sendMail.Info.Attachments) { - if (!itemGUIDs[i]) + if (att.ItemGUID.IsEmpty()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } - Item* item = player->GetItemByGuid(itemGUIDs[i]); + Item* item = player->GetItemByGuid(att.ItemGUID); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) @@ -255,7 +238,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - if (COD && item->IsWrapped()) + if (sendMail.Info.Cod && item->IsWrapped()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; @@ -267,7 +250,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - items[i] = item; + items.push_back(item); } player->SendMailResult(0, MAIL_SEND, MAIL_OK); @@ -277,28 +260,27 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) bool needItemDelay = false; - MailDraft draft(subject, body); + MailDraft draft(sendMail.Info.Subject, sendMail.Info.Body); CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - if (items_count > 0 || money > 0) + if (!sendMail.Info.Attachments.empty() || sendMail.Info.SendMoney > 0) { bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE); - if (items_count > 0) + if (!sendMail.Info.Attachments.empty()) { - for (uint8 i = 0; i < items_count; ++i) + for (Item* item : items) { - Item* item = items[i]; if (log) { sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail item: %s (Entry: %u Count: %u) " "to: %s (%s) (Account: %u)", GetPlayerName().c_str(), GetGUIDLow(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), - receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); + sendMail.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable - player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); + player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SetOwnerGUID(receiverGuid); @@ -312,10 +294,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } - if (log && money > 0) + if (log && sendMail.Info.SendMoney > 0) { - sLog->outCommand(GetAccountId(), "GM %s (GUID: %u) (Account: %u) mail money: %u to: %s (%s) (Account: %u)", - GetPlayerName().c_str(), GetGUIDLow(), GetAccountId(), money, receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); + sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: %u to: %s (%s) (Account: %u)", + GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), sendMail.Info.SendMoney, sendMail.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } } @@ -323,32 +305,27 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // don't ask for COD if there are no items - if (items_count == 0) - COD = 0; + if (sendMail.Info.Attachments.empty()) + sendMail.Info.Cod = 0; // will delete item or place to receiver mail list draft - .AddMoney(money) - .AddCOD(COD) - .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); + .AddMoney(sendMail.Info.SendMoney) + .AddCOD(sendMail.Info.Cod) + .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), sendMail.Info.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); } //called when mail is read -void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) +void WorldSession::HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& markAsRead) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(markAsRead.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(markAsRead.MailID); if (m && m->state != MAIL_STATE_DELETED) { if (player->unReadMails) @@ -360,18 +337,12 @@ void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) } //called when client deletes mail -void WorldSession::HandleMailDelete(WorldPacket& recvData) +void WorldSession::HandleMailDelete(WorldPackets::Mail::MailDelete& mailDelete) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - recvData.read_skip<uint32>(); // mailTemplateId - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(mailDelete.Mailbox)) return; - Mail* m = _player->GetMail(mailId); + Mail* m = _player->GetMail(mailDelete.MailID); Player* player = _player; player->m_mailsUpdated = true; if (m) @@ -379,31 +350,25 @@ void WorldSession::HandleMailDelete(WorldPacket& recvData) // delete shouldn't show up for COD mails if (m->COD) { - player->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(mailDelete.MailID, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); return; } m->state = MAIL_STATE_DELETED; } - player->SendMailResult(mailId, MAIL_DELETED, MAIL_OK); + player->SendMailResult(mailDelete.MailID, MAIL_DELETED, MAIL_OK); } -void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) +void WorldSession::HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& returnToSender) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - recvData.read_skip<uint64>(); // original sender GUID for return to, not used - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(returnToSender.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(returnToSender.MailID); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime()) { - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(returnToSender.MailID, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); return; } //we can return mail now @@ -411,14 +376,14 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); - stmt->setUInt32(0, mailId); + stmt->setUInt32(0, returnToSender.MailID); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); - stmt->setUInt32(0, mailId); + stmt->setUInt32(0, returnToSender.MailID); trans->Append(stmt); - player->RemoveMail(mailId); + player->RemoveMail(returnToSender.MailID); // only return mail if the player exists (and delete if not existing) if (m->messageType == MAIL_NORMAL && m->sender) @@ -448,54 +413,47 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) CharacterDatabase.CommitTransaction(trans); delete m; //we can deallocate old mail - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); + player->SendMailResult(returnToSender.MailID, MAIL_RETURNED_TO_SENDER, MAIL_OK); } //called when player takes item attached in mail -void WorldSession::HandleMailTakeItem(WorldPacket& recvData) +void WorldSession::HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& takeItem) { - ObjectGuid mailbox; - uint32 mailId; - uint32 itemId; - recvData >> mailbox; - recvData >> mailId; - recvData >> itemId; // item guid low - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(takeItem.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(takeItem.MailID); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime()) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // verify that the mail has the item to avoid cheaters taking COD items without paying - if (std::find_if(m->items.begin(), m->items.end(), [itemId](MailItemInfo info){ return info.item_guid == itemId; }) == m->items.end()) + if (std::find_if(m->items.begin(), m->items.end(), [attachId = uint32(takeItem.AttachID)](MailItemInfo info){ return info.item_guid == attachId; }) == m->items.end()) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if (!player->HasEnoughMoney(m->COD)) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); + player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } - Item* it = player->GetMItem(itemId); + Item* it = player->GetMItem(takeItem.AttachID); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); if (msg == EQUIP_ERR_OK) { CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - m->RemoveItem(itemId); - m->removedItems.push_back(itemId); + m->RemoveItem(takeItem.AttachID); + m->removedItems.push_back(takeItem.AttachID); if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail { @@ -549,34 +507,29 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); + player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_OK, 0, takeItem.AttachID, count); } else - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); + player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); } -void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) +void WorldSession::HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& takeMoney) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(takeMoney.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(takeMoney.MailID); if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime()) { - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(takeMoney.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } if (!player->ModifyMoney(m->money, false)) { - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); + player->SendMailResult(takeMoney.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); return; } @@ -584,7 +537,7 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + player->SendMailResult(takeMoney.MailID, MAIL_MONEY_TAKEN, MAIL_OK); // save money and mail to prevent cheating CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); @@ -594,139 +547,43 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) } //called when player lists his received mails -void WorldSession::HandleGetMailList(WorldPacket& recvData) +void WorldSession::HandleGetMailList(WorldPackets::Mail::MailGetList& getList) { - ObjectGuid mailbox; - recvData >> mailbox; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(getList.Mailbox)) return; Player* player = _player; - // client can't work with packets > max int16 value - const uint32 maxPacketSize = 32767; + WorldPackets::Mail::MailListResult response; + time_t curTime = GameTime::GetGameTime(); - uint32 mailsCount = 0; // real send to client mails amount - uint32 realCount = 0; // real mails amount - - 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 = GameTime::GetGameTime(); - - for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) + for (Mail* m : player->GetMails()) { - // Only first 50 mails are displayed - if (mailsCount >= 50) - { - realCount += 1; - continue; - } - // skip deleted or not delivered (deliver delay not expired) mails - if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) + if (m->state == MAIL_STATE_DELETED || curTime < m->deliver_time) continue; - uint8 item_count = (*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 > maxPacketSize) - { - realCount += 1; - continue; - } - - data << uint16(next_mail_size); // Message size - data << uint32((*itr)->messageID); // Message ID - data << uint8((*itr)->messageType); // Message Type - - switch ((*itr)->messageType) - { - case MAIL_NORMAL: // sender guid - data << ObjectGuid(HighGuid::Player, (*itr)->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? - break; - } - - data << uint32((*itr)->COD); // COD - data << uint32(0); // package (Package.dbc) - data << uint32((*itr)->stationery); // stationery (Stationery.dbc) - data << uint32((*itr)->money); // Gold - data << uint32((*itr)->checked); // flags - data << float(float((*itr)->expire_time - GameTime::GetGameTime())/DAY); // Time - data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) - data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 - data << (*itr)->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 index (0-6?) - data << uint8(i); - // item guid low? - data << uint32((item ? item->GetGUID().GetCounter() : 0)); - // entry - data << uint32((item ? item->GetEntry() : 0)); - for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) - { - data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); - } - // can be negative - data << int32((item ? item->GetItemRandomPropertyId() : 0)); - // unk - data << uint32((item ? item->GetItemSuffixFactor() : 0)); - // stack count - data << uint32((item ? item->GetCount() : 0)); - // charges - data << uint32((item ? item->GetSpellCharges() : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0)); - // unknown wotlk - data << uint8((item && !item->IsLocked() ? 1 : 0)); - } - - ++realCount; - ++mailsCount; + response.AddMail(m, _player); } - 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); + SendPacket(response.Write()); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); } //used when player copies mail body to his inventory -void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) +void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& createTextItem) { - ObjectGuid mailbox; - uint32 mailId; - - recvData >> mailbox; - recvData >> mailId; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(createTextItem.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(createTextItem.MailID); if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime() || (m->checked & MAIL_CHECK_MASK_COPIED)) { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(createTextItem.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } @@ -752,7 +609,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); - TC_LOG_INFO("network", "HandleMailCreateTextItem mailid=%u", mailId); + TC_LOG_INFO("network", "HandleMailCreateTextItem mailid=%u", createTextItem.MailID); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); @@ -763,30 +620,27 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) player->m_mailsUpdated = true; player->StoreItem(dest, bodyItem, true); - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); + player->SendMailResult(createTextItem.MailID, MAIL_MADE_PERMANENT, MAIL_OK); } else { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); + player->SendMailResult(createTextItem.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); delete bodyItem; } } -void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recvData*/) +void WorldSession::HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& /*queryNextMailTime*/) { - WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); + WorldPackets::Mail::MailQueryNextTimeResult result; if (_player->unReadMails > 0) { - data << float(0); // float - data << uint32(0); // count + result.NextMailTime = 0.0f; - uint32 count = 0; time_t now = GameTime::GetGameTime(); std::set<uint32> sentSenders; - for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) + for (Mail* m : _player->GetMails()) { - Mail* m = (*itr); // must be not checked yet if (m->checked & MAIL_CHECK_MASK_READ) continue; @@ -799,25 +653,17 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recvData*/) if (sentSenders.count(m->sender)) continue; - data << uint64(m->messageType == MAIL_NORMAL ? ObjectGuid(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); + result.Next.emplace_back(m); sentSenders.insert(m->sender); - ++count; - if (count == 2) // do not display more than 2 mails + + // do not send more than 2 mails + if (sentSenders.size() > 2) break; } - - data.put<uint32>(4, count); } else - { - data << float(-DAY); - data << uint32(0); - } + result.NextMailTime = -DAY; - SendPacket(&data); + SendPacket(result.Write()); } diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 96fce970b95..75e7899a2c5 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -26,6 +26,7 @@ #include "GossipDef.h" #include "Item.h" #include "Log.h" +#include "MailPackets.h" #include "Map.h" #include "NPCPackets.h" #include "Opcodes.h" @@ -79,9 +80,9 @@ void WorldSession::SendTabardVendorActivate(ObjectGuid guid) void WorldSession::SendShowMailBox(ObjectGuid guid) { - WorldPacket data(SMSG_SHOW_MAILBOX, 8); - data << guid; - SendPacket(&data); + WorldPackets::Mail::ShowMailbox packet; + packet.PostmasterGUID = guid; + SendPacket(packet.Write()); } void WorldSession::HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet) diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 1b3d2006854..12f1fb37973 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -26,6 +26,7 @@ #include "GuildPackets.h" #include "LFGPackets.h" #include "NPCPackets.h" +#include "MailPackets.h" #include "MiscPackets.h" #include "PetPackets.h" #include "QueryPackets.h" diff --git a/src/server/game/Server/Packets/MailPackets.cpp b/src/server/game/Server/Packets/MailPackets.cpp new file mode 100644 index 00000000000..ffb85167ead --- /dev/null +++ b/src/server/game/Server/Packets/MailPackets.cpp @@ -0,0 +1,300 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "MailPackets.h" +#include "Item.h" +#include "Mail.h" +#include "Player.h" +#include "World.h" + +WorldPackets::Mail::MailAttachedItem::MailAttachedItem(::Item const* item, uint8 pos) +{ + Position = pos; + AttachID = item->GetGUID().GetCounter(); + ItemID = item->GetEntry(); + RandomPropertiesID = item->GetItemRandomPropertyId(); + RandomPropertiesSeed = item->GetItemSuffixFactor(); + Count = item->GetCount(); + Charges = item->GetSpellCharges(); + MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + Durability = item->GetInt32Value(ITEM_FIELD_DURABILITY); + Unlocked = !item->IsLocked(); + + for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; j++) + { + EnchantmentSlot slot = EnchantmentSlot(j); + EnchantmentID[slot] = item->GetEnchantmentId(slot); + EnchantmentDuration[slot] = item->GetEnchantmentDuration(slot); + EnchantmentCharges[slot] = item->GetEnchantmentCharges(slot); + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailAttachedItem const& att) +{ + data << uint8(att.Position); + data << int32(att.AttachID); + data << int32(att.ItemID); + for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++) + { + data << int32(att.EnchantmentID[i]); + data << int32(att.EnchantmentDuration[i]); + data << int32(att.EnchantmentCharges[i]); + } + data << int32(att.RandomPropertiesID); + data << int32(att.RandomPropertiesSeed); + data << int32(att.Count); + data << int32(att.Charges); + data << uint32(att.MaxDurability); + data << int32(att.Durability); + data << bool(att.Unlocked); + + return data; +} + +WorldPackets::Mail::MailListEntry::MailListEntry(::Mail const* mail, ::Player* player) +{ + MailID = mail->messageID; + SenderType = mail->messageType; + + switch (mail->messageType) + { + case MAIL_NORMAL: + SenderCharacter = ObjectGuid::Create<HighGuid::Player>(mail->sender); + break; + case MAIL_CREATURE: + case MAIL_GAMEOBJECT: + case MAIL_AUCTION: + case MAIL_CALENDAR: + AltSenderID = mail->sender; + break; + } + + Cod = mail->COD; + StationeryID = mail->stationery; + SentMoney = mail->money; + Flags = mail->checked; + DaysLeft = float(mail->expire_time - time(nullptr)) / DAY; + MailTemplateID = mail->mailTemplateId; + Subject = mail->subject; + Body = mail->body; + + for (uint8 i = 0; i < mail->items.size(); i++) + if (::Item* item = player->GetMItem(mail->items[i].item_guid)) + Attachments.emplace_back(item, i); +} + +std::size_t WorldPackets::Mail::MailListEntry::GetPacketSize() const +{ + return sizeof(uint16) + sizeof(int32) + sizeof(uint8) + (SenderCharacter ? sizeof(uint64) : 0) + (AltSenderID ? sizeof(int32) : 0) + + sizeof(uint32) + sizeof(int32) + sizeof(int32) + sizeof(uint32) + sizeof(int32) + sizeof(float) + sizeof(int32) + + Subject.length() + 1 + Body.length() + 1 + sizeof(uint8) + Attachments.size() * MailAttachedItem::GetPacketSize(); +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailListEntry const& entry) +{ + data << uint16(entry.GetPacketSize()); + data << int32(entry.MailID); + data << uint8(entry.SenderType); + if (entry.SenderCharacter) + data << *entry.SenderCharacter; + else if (entry.AltSenderID) + data << int32(*entry.AltSenderID); + + data << uint32(entry.Cod); + data << int32(entry.PackageID); + data << int32(entry.StationeryID); + data << uint32(entry.SentMoney); + data << int32(entry.Flags); + data << float(entry.DaysLeft); + data << int32(entry.MailTemplateID); + data << entry.Subject; + data << entry.Body; + data << uint8(entry.Attachments.size()); + + for (WorldPackets::Mail::MailAttachedItem const& att : entry.Attachments) + data << att; + + return data; +} + +void WorldPackets::Mail::MailGetList::Read() +{ + _worldPacket >> Mailbox; +} + +WorldPackets::Mail::MailListResult::MailListResult() : ServerPacket(SMSG_MAIL_LIST_RESULT, 8) +{ + _worldPacket << int32(0); // TotalNumRecords + _worldPacket << uint8(0); // Mails.size() +} + +WorldPacket const* WorldPackets::Mail::MailListResult::Write() +{ + _worldPacket.put<int32>(0, TotalNumRecords); + _worldPacket.put<uint8>(4, Mails.size()); + + return &_worldPacket; +} + +void WorldPackets::Mail::MailListResult::AddMail(::Mail const* mail, Player* player) +{ + ++TotalNumRecords; + if (Mails.size() >= 50 || _maxPacketSizeReached) + return; + + MailListEntry packetEntry(mail, player); + if (_worldPacket.size() + packetEntry.GetPacketSize() >= std::numeric_limits<int16>::max()) + { + _maxPacketSizeReached = true; + return; + } + + _worldPacket << Mails.emplace_back(std::move(packetEntry)); +} + +void WorldPackets::Mail::MailCreateTextItem::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; +} + +void WorldPackets::Mail::SendMail::Read() +{ + _worldPacket >> Info.Mailbox; + _worldPacket >> Info.Target; + _worldPacket >> Info.Subject; + _worldPacket >> Info.Body; + _worldPacket >> Info.StationeryID; + _worldPacket >> Info.PackageID; + Info.Attachments.resize(_worldPacket.read<uint8>()); + + for (auto& att : Info.Attachments) + { + _worldPacket >> att.AttachPosition; + _worldPacket >> att.ItemGUID; + } + + _worldPacket >> Info.SendMoney; + _worldPacket >> Info.Cod; + _worldPacket.read_skip<uint64>(); + _worldPacket.read_skip<uint8>(); +} + +void WorldPackets::Mail::MailReturnToSender::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + _worldPacket >> SenderGUID; +} + +WorldPacket const* WorldPackets::Mail::MailCommandResult::Write() +{ + _worldPacket << uint32(MailID); + _worldPacket << uint32(Command); + _worldPacket << uint32(ErrorCode); + + if (ErrorCode == MAIL_ERR_EQUIP_ERROR) + _worldPacket << uint32(BagResult); + + if (Command == MAIL_ITEM_TAKEN) + { + if (ErrorCode == MAIL_OK || ErrorCode == MAIL_ERR_ITEM_HAS_EXPIRED) + { + _worldPacket << uint32(AttachID); + _worldPacket << uint32(QtyInInventory); + } + } + + return &_worldPacket; +} + +void WorldPackets::Mail::MailMarkAsRead::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; +} + +void WorldPackets::Mail::MailDelete::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + _worldPacket >> DeleteReason; +} + +void WorldPackets::Mail::MailTakeItem::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + _worldPacket >> AttachID; +} + +void WorldPackets::Mail::MailTakeMoney::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; +} + +WorldPackets::Mail::MailQueryNextTimeResult::MailNextTimeEntry::MailNextTimeEntry(::Mail const* mail) +{ + switch (mail->messageType) + { + case MAIL_NORMAL: + SenderGuid = ObjectGuid::Create<HighGuid::Player>(mail->sender); + break; + case MAIL_AUCTION: + case MAIL_CREATURE: + case MAIL_GAMEOBJECT: + case MAIL_CALENDAR: + AltSenderID = mail->sender; + break; + } + + TimeLeft = mail->deliver_time - time(nullptr); + AltSenderType = mail->messageType; + StationeryID = mail->stationery; +} + +WorldPacket const* WorldPackets::Mail::MailQueryNextTimeResult::Write() +{ + _worldPacket << float(NextMailTime); + _worldPacket << int32(Next.size()); + + for (auto const& entry : Next) + { + _worldPacket << entry.SenderGuid; + _worldPacket << int32(entry.AltSenderID); + _worldPacket << int32(entry.AltSenderType); + _worldPacket << int32(entry.StationeryID); + _worldPacket << float(entry.TimeLeft); + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Mail::NotifyReceivedMail::Write() +{ + _worldPacket << float(Delay); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Mail::ShowMailbox::Write() +{ + _worldPacket << PostmasterGUID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MailPackets.h b/src/server/game/Server/Packets/MailPackets.h new file mode 100644 index 00000000000..855cb459ca6 --- /dev/null +++ b/src/server/game/Server/Packets/MailPackets.h @@ -0,0 +1,269 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MailPackets_h__ +#define MailPackets_h__ + +#include "Packet.h" +#include "ItemDefines.h" +#include "Mail.h" +#include "Optional.h" +#include "PacketUtilities.h" + +namespace WorldPackets +{ + namespace Mail + { + struct MailAttachedItem + { + MailAttachedItem(::Item const* item, uint8 pos); + + static constexpr std::size_t GetPacketSize() + { + return sizeof(uint8) + sizeof(int32) + sizeof(int32) + MAX_INSPECTED_ENCHANTMENT_SLOT * (sizeof(int32) + sizeof(int32) + sizeof(int32)) + + sizeof(int32) + sizeof(int32) + sizeof(int32) + sizeof(int32) + sizeof(uint32) + sizeof(int32) + sizeof(bool); + } + + uint8 Position = 0; + int32 AttachID = 0; + int32 ItemID = 0; + int32 RandomPropertiesSeed = 0; + int32 RandomPropertiesID = 0; + int32 Count = 0; + int32 Charges = 0; + uint32 MaxDurability = 0; + int32 Durability = 0; + bool Unlocked = false; + std::array<uint32, MAX_INSPECTED_ENCHANTMENT_SLOT> EnchantmentID = { }; + std::array<uint32, MAX_INSPECTED_ENCHANTMENT_SLOT> EnchantmentDuration = { }; + std::array<uint32, MAX_INSPECTED_ENCHANTMENT_SLOT> EnchantmentCharges = { }; + }; + + struct MailListEntry + { + MailListEntry(::Mail const* mail, ::Player* player); + + std::size_t GetPacketSize() const; + + int32 MailID = 0; + uint8 SenderType = 0; + Optional<ObjectGuid> SenderCharacter; + Optional<uint32> AltSenderID; + uint32 Cod = 0; + int32 PackageID = 0; + int32 StationeryID = 0; + uint32 SentMoney = 0; + int32 Flags = 0; + float DaysLeft = 0.0f; + int32 MailTemplateID = 0; + std::string_view Subject; + std::string_view Body; + std::vector<MailAttachedItem> Attachments; + }; + + class MailGetList final : public ClientPacket + { + public: + MailGetList(WorldPacket&& packet) : ClientPacket(CMSG_GET_MAIL_LIST, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + }; + + class MailListResult final : public ServerPacket + { + public: + MailListResult(); + + WorldPacket const* Write() override; + + void AddMail(::Mail const* mail, Player* player); + + int32 TotalNumRecords = 0; + std::vector<MailListEntry> Mails; + + private: + bool _maxPacketSizeReached = false; + }; + + class MailCreateTextItem final : public ClientPacket + { + public: + MailCreateTextItem(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_CREATE_TEXT_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + uint32 MailID = 0; + }; + + class SendMail final : public ClientPacket + { + public: + struct StructSendMail + { + struct MailAttachment + { + uint8 AttachPosition = 0; + ObjectGuid ItemGUID; + }; + + ObjectGuid Mailbox; + int32 StationeryID = 0; + int32 PackageID = 0; + int32 SendMoney = 0; + int32 Cod = 0; + std::string Target; + String<255, Strings::NoHyperlinks> Subject; + String<7999, Strings::NoHyperlinks> Body; + Array<MailAttachment, MAX_MAIL_ITEMS> Attachments; + }; + + SendMail(WorldPacket&& packet) : ClientPacket(CMSG_SEND_MAIL, std::move(packet)) { } + + void Read() override; + + StructSendMail Info; + }; + + class MailCommandResult final : public ServerPacket + { + public: + MailCommandResult() : ServerPacket(SMSG_SEND_MAIL_RESULT) { } + + WorldPacket const* Write() override; + + uint32 MailID = 0; + uint32 Command = 0; + uint32 ErrorCode = 0; + uint32 BagResult = 0; + uint32 AttachID = 0; + uint32 QtyInInventory = 0; + }; + + class MailReturnToSender final : public ClientPacket + { + public: + MailReturnToSender(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_RETURN_TO_SENDER, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + ObjectGuid SenderGUID; + }; + + class MailMarkAsRead final : public ClientPacket + { + public: + MailMarkAsRead(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_MARK_AS_READ, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + }; + + class MailDelete final : public ClientPacket + { + public: + MailDelete(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_DELETE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + int32 DeleteReason = 0; + }; + + class MailTakeItem final : public ClientPacket + { + public: + MailTakeItem(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_TAKE_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + int32 AttachID = 0; + }; + + class MailTakeMoney final : public ClientPacket + { + public: + MailTakeMoney(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_TAKE_MONEY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + }; + + class MailQueryNextMailTime final : public ClientPacket + { + public: + MailQueryNextMailTime(WorldPacket&& packet) : ClientPacket(MSG_QUERY_NEXT_MAIL_TIME, std::move(packet)) { } + + void Read() override { } + }; + + class MailQueryNextTimeResult final : public ServerPacket + { + public: + struct MailNextTimeEntry + { + MailNextTimeEntry(::Mail const* mail); + + ObjectGuid SenderGuid; + float TimeLeft = 0.0f; + int32 AltSenderID = 0; + int32 AltSenderType = 0; + int32 StationeryID = 0; + }; + + MailQueryNextTimeResult() : ServerPacket(MSG_QUERY_NEXT_MAIL_TIME, 8) { } + + WorldPacket const* Write() override; + + float NextMailTime = 0.0f; + std::vector<MailNextTimeEntry> Next; + }; + + class NotifyReceivedMail : ServerPacket + { + public: + NotifyReceivedMail() : ServerPacket(SMSG_RECEIVED_MAIL, 4) { } + + WorldPacket const* Write() override; + + float Delay = 0.0f; + }; + + class ShowMailbox final : public ServerPacket + { + public: + ShowMailbox() : ServerPacket(SMSG_SHOW_MAILBOX, 16) { } + + WorldPacket const* Write() override; + + ObjectGuid PostmasterGUID; + }; + } +} + +#endif // MailPackets_h__ diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index e19c81b54db..1a3917dd325 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -142,16 +142,26 @@ namespace WorldPackets class GuildSetGuildMaster; class SaveGuildEmblem; } + namespace LFG { class LFGJoin; class LFGLeave; } - namespace NPC + + namespace Mail { - class Hello; - class TrainerBuySpell; + class MailCreateTextItem; + class MailDelete; + class MailGetList; + class MailMarkAsRead; + class MailQueryNextMailTime; + class MailReturnToSender; + class MailTakeItem; + class MailTakeMoney; + class SendMail; } + namespace Misc { class CompleteCinematic; @@ -166,6 +176,12 @@ namespace WorldPackets class ResurrectResponse; } + namespace NPC + { + class Hello; + class TrainerBuySpell; + } + namespace Pet { class DismissCritter; @@ -816,16 +832,16 @@ class TC_GAME_API WorldSession void HandleAutoStoreBankItemOpcode(WorldPackets::Bank::AutoStoreBankItem& packet); void HandleBuyBankSlotOpcode(WorldPackets::Bank::BuyBankSlot& buyBankSlot); - void HandleGetMailList(WorldPacket& recvData); - void HandleSendMail(WorldPacket& recvData); - void HandleMailTakeMoney(WorldPacket& recvData); - void HandleMailTakeItem(WorldPacket& recvData); - void HandleMailMarkAsRead(WorldPacket& recvData); - void HandleMailReturnToSender(WorldPacket& recvData); - void HandleMailDelete(WorldPacket& recvData); + void HandleGetMailList(WorldPackets::Mail::MailGetList& getList); + void HandleSendMail(WorldPackets::Mail::SendMail& sendMail); + void HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& takeMoney); + void HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& takeItem); + void HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& markAsRead); + void HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& returnToSender); + void HandleMailDelete(WorldPackets::Mail::MailDelete& mailDelete); void HandleItemTextQuery(WorldPacket& recvData); - void HandleMailCreateTextItem(WorldPacket& recvData); - void HandleQueryNextMailTime(WorldPacket& recvData); + void HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& createTextItem); + void HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& queryNextMailTime); void HandleSplitItemOpcode(WorldPacket& recvPacket); void HandleSwapInvItemOpcode(WorldPacket& recvPacket); |