AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
mail_commandscript Class Reference
Inheritance diagram for mail_commandscript:
CommandScript ScriptObject

Public Member Functions

 mail_commandscript ()
 
ChatCommandTable GetCommands () const override
 
- Public Member Functions inherited from ScriptObject
virtual bool IsDatabaseBound () const
 
virtual bool isAfterLoadScript () const
 
virtual void checkValidity ()
 
const std::string & GetName () const
 
uint16 GetTotalAvailableHooks ()
 

Static Public Member Functions

static char const * GetMailTypeString (uint8 messageType)
 
static char const * GetMailStationeryString (uint8 stationery)
 
static std::string GetItemListString (std::vector< MailItemInfo > const &items)
 
static bool HandleMailListCommand (ChatHandler *handler, Optional< PlayerIdentifier > target)
 
static bool HandleMailReturnCommand (ChatHandler *handler, PlayerIdentifier target, uint32 mailId)
 

Additional Inherited Members

- Protected Member Functions inherited from CommandScript
 CommandScript (const char *name)
 
- Protected Member Functions inherited from ScriptObject
 ScriptObject (const char *name, uint16 totalAvailableHooks=0)
 
virtual ~ScriptObject ()=default
 

Detailed Description

Constructor & Destructor Documentation

◆ mail_commandscript()

mail_commandscript::mail_commandscript ( )
inline
37: CommandScript("mail_commandscript") { }
Definition CommandScript.h:25

Member Function Documentation

◆ GetCommands()

ChatCommandTable mail_commandscript::GetCommands ( ) const
inlineoverridevirtual

Implements CommandScript.

40 {
41 static ChatCommandTable mailCommandTable =
42 {
43 { "list", HandleMailListCommand, SEC_GAMEMASTER, Console::Yes },
44 { "return", HandleMailReturnCommand, SEC_GAMEMASTER, Console::Yes }
45 };
46
47 static ChatCommandTable commandTable =
48 {
49 { "mail", mailCommandTable }
50 };
51
52 return commandTable;
53 }
@ SEC_GAMEMASTER
Definition Common.h:59
static bool HandleMailReturnCommand(ChatHandler *handler, PlayerIdentifier target, uint32 mailId)
Definition cs_mail.cpp:188
static bool HandleMailListCommand(ChatHandler *handler, Optional< PlayerIdentifier > target)
Definition cs_mail.cpp:99
std::vector< ChatCommandBuilder > ChatCommandTable
Definition ChatCommand.h:46

References HandleMailListCommand(), HandleMailReturnCommand(), and SEC_GAMEMASTER.

◆ GetItemListString()

static std::string mail_commandscript::GetItemListString ( std::vector< MailItemInfo > const &  items)
inlinestatic
84 {
85 if (items.empty())
86 return "none";
87
88 std::string result;
89 for (size_t i = 0; i < items.size(); ++i)
90 {
91 if (i > 0)
92 result += ", ";
93
94 result += Acore::StringFormat("{}(guid:{})", items[i].item_template, items[i].item_guid);
95 }
96 return result;
97 }
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default AC string format function.
Definition StringFormat.h:44

References Acore::StringFormat().

Referenced by HandleMailListCommand().

◆ GetMailStationeryString()

static char const * mail_commandscript::GetMailStationeryString ( uint8  stationery)
inlinestatic
69 {
70 switch (stationery)
71 {
72 case MAIL_STATIONERY_TEST: return "Test";
73 case MAIL_STATIONERY_DEFAULT: return "Default";
74 case MAIL_STATIONERY_GM: return "GM";
75 case MAIL_STATIONERY_AUCTION: return "Auction";
76 case MAIL_STATIONERY_VAL: return "Valentine";
77 case MAIL_STATIONERY_CHR: return "Christmas";
78 case MAIL_STATIONERY_ORP: return "Orphan";
79 default: return "Unknown";
80 }
81 }
@ MAIL_STATIONERY_TEST
Definition Mail.h:57
@ MAIL_STATIONERY_GM
Definition Mail.h:59
@ MAIL_STATIONERY_CHR
Definition Mail.h:62
@ MAIL_STATIONERY_ORP
Definition Mail.h:63
@ MAIL_STATIONERY_DEFAULT
Definition Mail.h:58
@ MAIL_STATIONERY_VAL
Definition Mail.h:61
@ MAIL_STATIONERY_AUCTION
Definition Mail.h:60

References MAIL_STATIONERY_AUCTION, MAIL_STATIONERY_CHR, MAIL_STATIONERY_DEFAULT, MAIL_STATIONERY_GM, MAIL_STATIONERY_ORP, MAIL_STATIONERY_TEST, and MAIL_STATIONERY_VAL.

Referenced by HandleMailListCommand().

◆ GetMailTypeString()

static char const * mail_commandscript::GetMailTypeString ( uint8  messageType)
inlinestatic
56 {
57 switch (messageType)
58 {
59 case MAIL_NORMAL: return "Normal";
60 case MAIL_AUCTION: return "Auction";
61 case MAIL_CREATURE: return "Creature";
62 case MAIL_GAMEOBJECT: return "GameObject";
63 case MAIL_CALENDAR: return "Calendar";
64 default: return "Unknown";
65 }
66 }
@ MAIL_AUCTION
Definition Mail.h:38
@ MAIL_GAMEOBJECT
Definition Mail.h:40
@ MAIL_CREATURE
Definition Mail.h:39
@ MAIL_CALENDAR
Definition Mail.h:41
@ MAIL_NORMAL
Definition Mail.h:37

References MAIL_AUCTION, MAIL_CALENDAR, MAIL_CREATURE, MAIL_GAMEOBJECT, and MAIL_NORMAL.

Referenced by HandleMailListCommand().

◆ HandleMailListCommand()

static bool mail_commandscript::HandleMailListCommand ( ChatHandler handler,
Optional< PlayerIdentifier target 
)
inlinestatic
100 {
101 if (!target)
102 target = PlayerIdentifier::FromTargetOrSelf(handler);
103
104 if (!target)
105 return false;
106
107 Player* player = target->GetConnectedPlayer();
108
109 if (player)
110 {
111 PlayerMails const& mails = player->GetMails();
112
113 if (mails.empty())
114 {
115 handler->PSendSysMessage(LANG_MAIL_LIST_EMPTY, handler->playerLink(target->GetName()));
116 return true;
117 }
118
119 handler->PSendSysMessage(LANG_MAIL_LIST_HEADER, handler->playerLink(target->GetName()));
120
121 for (Mail const* mail : mails)
122 {
123 std::string senderName;
124 if (mail->messageType == MAIL_NORMAL)
125 sCharacterCache->GetCharacterNameByGuid(ObjectGuid(HighGuid::Player, mail->sender), senderName);
126
127 std::string expireStr = Acore::Time::TimeToTimestampStr(Seconds(mail->expire_time));
128 std::string deliverStr = Acore::Time::TimeToTimestampStr(Seconds(mail->deliver_time));
129
131 mail->messageID, GetMailTypeString(mail->messageType), GetMailStationeryString(mail->stationery),
132 mail->mailTemplateId, mail->sender, senderName, mail->receiver,
133 expireStr, deliverStr, mail->money, mail->COD, mail->checked, GetItemListString(mail->items));
134 }
135 }
136 else
137 {
138 ObjectGuid::LowType lowGuid = target->GetGUID().GetCounter();
139
140 QueryResult result = CharacterDatabase.Query(
141 "SELECT id, messageType, sender, receiver, subject, body, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId"
142 " FROM mail WHERE receiver = {} AND deliver_time <= {} ORDER BY id DESC",
143 lowGuid, GameTime::GetGameTime().count());
144
145 if (!result)
146 {
147 handler->PSendSysMessage(LANG_MAIL_LIST_EMPTY, handler->playerLink(target->GetName()));
148 return true;
149 }
150
151 handler->PSendSysMessage(LANG_MAIL_LIST_HEADER, handler->playerLink(target->GetName()));
152
153 do
154 {
155 Field* fields = result->Fetch();
156 uint32 messageID = fields[0].Get<uint32>();
157 uint8 messageType = fields[1].Get<uint8>();
158 uint32 sender = fields[2].Get<uint32>();
159 uint32 receiver = fields[3].Get<uint32>();
160 // fields[4] = subject (skipped)
161 // fields[5] = body (skipped)
162 uint32 expireTime = fields[6].Get<uint32>();
163 uint32 deliverTime = fields[7].Get<uint32>();
164 uint32 money = fields[8].Get<uint32>();
165 uint32 cod = fields[9].Get<uint32>();
166 uint32 checked = fields[10].Get<uint32>();
167 uint8 stationery = fields[11].Get<uint8>();
168 uint16 mailTemplate = fields[12].Get<uint16>();
169
170 std::string senderName;
171 if (messageType == MAIL_NORMAL)
172 sCharacterCache->GetCharacterNameByGuid(ObjectGuid(HighGuid::Player, sender), senderName);
173
174 std::string expireStr = Acore::Time::TimeToTimestampStr(Seconds(expireTime));
175 std::string deliverStr = Acore::Time::TimeToTimestampStr(Seconds(deliverTime));
176
177 // For offline players we don't have item details loaded
179 messageID, GetMailTypeString(messageType), GetMailStationeryString(stationery),
180 mailTemplate, sender, senderName, receiver,
181 expireStr, deliverStr, money, cod, checked, "N/A (offline)");
182 } while (result->NextRow());
183 }
184
185 return true;
186 }
#define sCharacterCache
Definition CharacterCache.h:83
std::shared_ptr< ResultSet > QueryResult
Definition DatabaseEnvFwd.h:27
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition DatabaseEnv.cpp:21
std::uint8_t uint8
Definition Define.h:109
std::uint32_t uint32
Definition Define.h:107
std::uint16_t uint16
Definition Define.h:108
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:30
@ LANG_MAIL_LIST_ENTRY
Definition Language.h:1220
@ LANG_MAIL_LIST_HEADER
Definition Language.h:1219
@ LANG_MAIL_LIST_EMPTY
Definition Language.h:1221
std::deque< Mail * > PlayerMails
Definition Player.h:68
std::string playerLink(std::string const &name) const
Definition Chat.h:231
void PSendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition Chat.cpp:211
Class used to access individual fields of database query result.
Definition Field.h:98
std::enable_if_t< std::is_arithmetic_v< T >, T > Get() const
Definition Field.h:112
Definition ObjectGuid.h:118
uint32 LowType
Definition ObjectGuid.h:122
Definition Player.h:1084
PlayerMails const & GetMails() const
Definition Player.h:1667
static std::string GetItemListString(std::vector< MailItemInfo > const &items)
Definition cs_mail.cpp:83
static char const * GetMailTypeString(uint8 messageType)
Definition cs_mail.cpp:55
static char const * GetMailStationeryString(uint8 stationery)
Definition cs_mail.cpp:68
AC_COMMON_API std::string TimeToTimestampStr(Seconds time=0s, std::string_view fmt={})
Definition Timer.cpp:272
Seconds GetGameTime()
Definition GameTime.cpp:38
static Optional< PlayerIdentifier > FromTargetOrSelf(ChatHandler *handler)
Definition ChatCommandTags.h:184
Definition Mail.h:167

References CharacterDatabase, Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(), Field::Get(), GameTime::GetGameTime(), GetItemListString(), Player::GetMails(), GetMailStationeryString(), GetMailTypeString(), LANG_MAIL_LIST_EMPTY, LANG_MAIL_LIST_ENTRY, LANG_MAIL_LIST_HEADER, MAIL_NORMAL, Player, ChatHandler::playerLink(), ChatHandler::PSendSysMessage(), sCharacterCache, and Acore::Time::TimeToTimestampStr().

Referenced by GetCommands().

◆ HandleMailReturnCommand()

static bool mail_commandscript::HandleMailReturnCommand ( ChatHandler handler,
PlayerIdentifier  target,
uint32  mailId 
)
inlinestatic
189 {
190 // Query mail data from DB so this works for offline players
191 QueryResult result = CharacterDatabase.Query(
192 "SELECT messageType, sender, receiver, subject, body, money, mailTemplateId, checked, deliver_time"
193 " FROM mail WHERE id = {}", mailId);
194
195 if (!result)
196 {
198 return true;
199 }
200
201 Field* fields = result->Fetch();
202 uint8 messageType = fields[0].Get<uint8>();
203 uint32 sender = fields[1].Get<uint32>();
204 uint32 receiver = fields[2].Get<uint32>();
205 std::string subject = fields[3].Get<std::string>();
206 std::string body = fields[4].Get<std::string>();
207 uint32 money = fields[5].Get<uint32>();
208 uint16 mailTemplate = fields[6].Get<uint16>();
209 uint32 checked = fields[7].Get<uint32>();
210 uint32 deliverTime = fields[8].Get<uint32>();
211
212 // Reject undelivered mail, same as the core handler
213 if (deliverTime > GameTime::GetGameTime().count())
214 {
216 return true;
217 }
218
219 // Verify the mail belongs to the target player
220 if (receiver != target.GetGUID().GetCounter())
221 {
223 return true;
224 }
225
226 if (messageType != MAIL_NORMAL)
227 {
229 return true;
230 }
231
232 if (!sender)
233 {
235 return true;
236 }
237
238 if (checked & MAIL_CHECK_MASK_RETURNED)
239 {
241 return true;
242 }
243
244 Player* player = target.GetConnectedPlayer();
245
246 // Run the same script hook as the client return handler, failing early before any deletions
247 if (player)
248 {
249 Mail* m = player->GetMail(mailId);
250 if (m)
251 {
252 ObjectGuid senderGuid = ObjectGuid(HighGuid::Player, sender);
253
254 if (m->HasItems())
255 {
256 for (auto const& itemInfo : m->items)
257 {
258 Item* item = player->GetMItem(itemInfo.item_guid);
259 if (item && !sScriptMgr->OnPlayerCanSendMail(player, senderGuid, ObjectGuid::Empty, subject, body, money, 0, item))
260 {
262 return true;
263 }
264 }
265 }
266 else if (!sScriptMgr->OnPlayerCanSendMail(player, senderGuid, ObjectGuid::Empty, subject, body, money, 0, nullptr))
267 {
269 return true;
270 }
271 }
272 }
273
274 // Same logic as WorldSession::HandleReturnToSender
275 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
276
278 stmt->SetData(0, mailId);
279 trans->Append(stmt);
280
281 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
282 stmt->SetData(0, mailId);
283 trans->Append(stmt);
284
285 MailDraft draft(subject, body);
286 if (mailTemplate)
287 draft = MailDraft(mailTemplate, false);
288
289 if (player)
290 {
291 // Online: same logic as WorldSession::HandleReturnToSender
292 // Get pointer before RemoveMail (which removes from deque but does not delete the object)
293 Mail* m = player->GetMail(mailId);
294
295 player->RemoveMail(mailId);
296
297 if (m && m->HasItems())
298 {
299 for (auto const& itemInfo : m->items)
300 {
301 if (Item* item = player->GetMItem(itemInfo.item_guid))
302 draft.AddItem(item);
303
304 player->RemoveMItem(itemInfo.item_guid);
305 }
306 }
307
308 delete m;
309 }
310 else
311 {
312 // Offline: load Item* objects from DB using same query shape as CHAR_SEL_MAILITEMS
313 // (LEFT JOIN to handle dangling mail_items) and same logic as Player::_LoadMailedItem
314 QueryResult itemResult = CharacterDatabase.Query(
315 "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments,"
316 " randomPropertyId, durability, playedTime, text, mi.item_guid, itemEntry, ii.owner_guid"
317 " FROM mail_items mi LEFT JOIN item_instance ii ON mi.item_guid = ii.guid"
318 " WHERE mi.mail_id = {}", mailId);
319
320 if (itemResult)
321 {
322 do
323 {
324 Field* itemFields = itemResult->Fetch();
325 uint32 itemGuid = itemFields[11].Get<uint32>();
326 uint32 itemEntry = itemFields[12].Get<uint32>();
327
328 // Handle dangling mail_items (missing item_instance)
329 if (!itemEntry)
330 {
331 LOG_ERROR("misc", "cs_mail: Mail #{} has dangling mail_items row for item_guid {}. Cleaning up.", mailId, itemGuid);
332
334 delStmt->SetData(0, itemGuid);
335 trans->Append(delStmt);
336 continue;
337 }
338
339 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
340 if (!proto)
341 {
342 LOG_ERROR("misc", "cs_mail: Mail #{} has unknown item (entry: {}, guid: {}). Cleaning up.", mailId, itemEntry, itemGuid);
343
345 delStmt->SetData(0, itemGuid);
346 trans->Append(delStmt);
347 continue;
348 }
349
350 Item* item = NewItemOrBag(proto);
351 ObjectGuid ownerGuid = itemFields[13].Get<uint32>()
352 ? ObjectGuid::Create<HighGuid::Player>(itemFields[13].Get<uint32>())
353 : ObjectGuid::Empty;
354
355 if (!item->LoadFromDB(itemGuid, ownerGuid, itemFields, itemEntry))
356 {
357 LOG_ERROR("misc", "cs_mail: Item (GUID: {}) in mail #{} failed to load. Cleaning up.", itemGuid, mailId);
358
360 delStmt->SetData(0, itemGuid);
361 trans->Append(delStmt);
362
363 item->FSetState(ITEM_REMOVED);
365 item->SaveToDB(nullTrans);
366 return true;
367 }
368
369 draft.AddItem(item);
370 } while (itemResult->NextRow());
371 }
372 }
373
374 uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver));
375 draft.AddMoney(money).SendReturnToSender(accountId, receiver, sender, trans);
376
377 CharacterDatabase.CommitTransaction(trans);
378
379 sCharacterCache->DecreaseCharacterMailCount(ObjectGuid(HighGuid::Player, receiver));
380
381 handler->PSendSysMessage(LANG_MAIL_RETURN_SUCCESS, mailId, handler->playerLink(target.GetName()));
382 return true;
383 }
Item * NewItemOrBag(ItemTemplate const *proto)
Definition Bag.h:67
@ CHAR_DEL_INVALID_MAIL_ITEM
Definition CharacterDatabase.h:113
@ CHAR_DEL_MAIL_BY_ID
Definition CharacterDatabase.h:110
@ CHAR_DEL_MAIL_ITEM_BY_ID
Definition CharacterDatabase.h:382
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
Definition DatabaseEnvFwd.h:69
@ ITEM_REMOVED
Definition Item.h:212
@ LANG_MAIL_RETURN_NOT_NORMAL
Definition Language.h:1224
@ LANG_MAIL_RETURN_ALREADY_RETURNED
Definition Language.h:1226
@ LANG_MAIL_RETURN_HOOK_BLOCKED
Definition Language.h:1227
@ LANG_MAIL_RETURN_NO_SENDER
Definition Language.h:1225
@ LANG_MAIL_RETURN_NOT_FOUND
Definition Language.h:1223
@ LANG_MAIL_RETURN_SUCCESS
Definition Language.h:1222
#define LOG_ERROR(filterType__,...)
Definition Log.h:158
@ MAIL_CHECK_MASK_RETURNED
Definition Mail.h:48
#define sObjectMgr
Definition ObjectMgr.h:1712
#define sScriptMgr
Definition ScriptMgr.h:734
void SendErrorMessage(uint32 entry)
Definition Chat.cpp:216
Definition Item.h:220
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field *fields, uint32 entry)
Definition Item.cpp:419
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:336
void FSetState(ItemUpdateState state)
Definition Item.h:330
Definition Mail.h:119
LowType GetCounter() const
Definition ObjectGuid.h:145
static ObjectGuid const Empty
Definition ObjectGuid.h:120
void RemoveMail(uint32 id)
Definition Player.cpp:2825
bool RemoveMItem(ObjectGuid::LowType itemLowGuid)
Definition Player.h:1695
Item * GetMItem(ObjectGuid::LowType itemLowGuid)
Definition Player.h:1682
Mail * GetMail(uint32 id)
Definition Player.cpp:3795
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition PreparedStatement.h:77
Definition PreparedStatement.h:157
ObjectGuid GetGUID() const
Definition ChatCommandTags.h:176
std::string const & GetName() const
Definition ChatCommandTags.h:175
Player * GetConnectedPlayer() const
Definition ChatCommandTags.h:178
Definition ItemTemplate.h:619
bool HasItems() const
Definition Mail.h:206

References MailDraft::AddItem(), MailDraft::AddMoney(), CHAR_DEL_INVALID_MAIL_ITEM, CHAR_DEL_MAIL_BY_ID, CHAR_DEL_MAIL_ITEM_BY_ID, CharacterDatabase, ObjectGuid::Empty, Item::FSetState(), Field::Get(), Acore::ChatCommands::PlayerIdentifier::GetConnectedPlayer(), ObjectGuid::GetCounter(), GameTime::GetGameTime(), Acore::ChatCommands::PlayerIdentifier::GetGUID(), Player::GetMail(), Player::GetMItem(), Acore::ChatCommands::PlayerIdentifier::GetName(), Mail::HasItems(), ITEM_REMOVED, Mail::items, LANG_MAIL_RETURN_ALREADY_RETURNED, LANG_MAIL_RETURN_HOOK_BLOCKED, LANG_MAIL_RETURN_NO_SENDER, LANG_MAIL_RETURN_NOT_FOUND, LANG_MAIL_RETURN_NOT_NORMAL, LANG_MAIL_RETURN_SUCCESS, Item::LoadFromDB(), LOG_ERROR, MAIL_CHECK_MASK_RETURNED, MAIL_NORMAL, NewItemOrBag(), Player, ChatHandler::playerLink(), ChatHandler::PSendSysMessage(), Player::RemoveMail(), Player::RemoveMItem(), Item::SaveToDB(), sCharacterCache, ChatHandler::SendErrorMessage(), MailDraft::SendReturnToSender(), PreparedStatementBase::SetData(), sObjectMgr, and sScriptMgr.

Referenced by GetCommands().


The documentation for this class was generated from the following file: