aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-09-27 15:29:05 +0200
committerShauren <shauren.trinity@gmail.com>2020-09-27 15:29:32 +0200
commit93f6e7431a73acc2047739ddf6ec006f9ccb59ec (patch)
tree4f37410e3d5e7c3e57b97eda4865730eadc60c63
parent24c798ddaceac603901e5fa9dec96a276166cb5b (diff)
Core/PacketIO: Convert mail packets to classes
-rw-r--r--src/server/game/Entities/Player/Player.cpp27
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Handlers/MailHandler.cpp382
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp7
-rw-r--r--src/server/game/Server/Packets/AllPackets.h1
-rw-r--r--src/server/game/Server/Packets/MailPackets.cpp300
-rw-r--r--src/server/game/Server/Packets/MailPackets.h269
-rw-r--r--src/server/game/Server/WorldSession.h40
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);