TrinityCore
Loading...
Searching...
No Matches
TicketMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "TicketMgr.h"
19#include "CharacterCache.h"
20#include "Chat.h"
21#include "Common.h"
22#include "DatabaseEnv.h"
23#include "GameTime.h"
24#include "Language.h"
25#include "Log.h"
26#include "ObjectAccessor.h"
27#include "Opcodes.h"
28#include "Player.h"
29#include "World.h"
30#include "WorldPacket.h"
31#include "WorldSession.h"
32
33inline float GetAge(uint64 t) { return float(GameTime::GetGameTime() - t) / float(DAY); }
34
36// GM ticket
37GmTicket::GmTicket() : _id(0), _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
38 _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
39 _needResponse(false), _needMoreHelp(false) { }
40
41GmTicket::GmTicket(Player* player) : _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(GameTime::GetGameTime()), _lastModifiedTime(GameTime::GetGameTime()),
42 _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
43 _needResponse(false), _needMoreHelp(false)
44{
45 _id = sTicketMgr->GenerateTicketId();
46 _playerName = player->GetName();
47 _playerGuid = player->GetGUID();
48}
49
53
58
63
65{
66 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
67 // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp
68 uint8 index = 0;
69 _id = fields[ index].GetUInt32();
70 _type = TicketType(fields[++index].GetUInt8());
71 _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt32());
72 _playerName = fields[++index].GetString();
73 _message = fields[++index].GetString();
74 _createTime = fields[++index].GetUInt32();
75 _mapId = fields[++index].GetUInt16();
76 _posX = fields[++index].GetFloat();
77 _posY = fields[++index].GetFloat();
78 _posZ = fields[++index].GetFloat();
79 _lastModifiedTime = fields[++index].GetUInt32();
80 _closedBy = fields[++index].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[index].GetUInt32()) : ObjectGuid::Empty;
81 _assignedTo = fields[++index].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[index].GetUInt32()) : ObjectGuid::Empty;
82 _comment = fields[++index].GetString();
83 _response = fields[++index].GetString();
84 _completed = fields[++index].GetBool();
85 _escalatedStatus = GMTicketEscalationStatus(fields[++index].GetUInt8());
86 _viewed = fields[++index].GetBool();
87 _needMoreHelp = fields[++index].GetBool();
88 return true;
89}
90
92{
93 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
94 // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
95 uint8 index = 0;
97 stmt->setUInt32( index, _id);
98 stmt->setUInt8 (++index, uint8(_type));
99 stmt->setUInt32(++index, _playerGuid.GetCounter());
100 stmt->setString(++index, _playerName);
101 stmt->setString(++index, _message);
102 stmt->setUInt32(++index, uint32(_createTime));
103 stmt->setUInt16(++index, _mapId);
104 stmt->setFloat (++index, _posX);
105 stmt->setFloat (++index, _posY);
106 stmt->setFloat (++index, _posZ);
107 stmt->setUInt32(++index, uint32(_lastModifiedTime));
108 stmt->setUInt32(++index, _closedBy.GetCounter());
109 stmt->setUInt32(++index, _assignedTo.GetCounter());
110 stmt->setString(++index, _comment);
111 stmt->setString(++index, _response);
112 stmt->setBool (++index, _completed);
113 stmt->setUInt8 (++index, uint8(_escalatedStatus));
114 stmt->setBool (++index, _viewed);
115 stmt->setBool (++index, _needMoreHelp);
116 stmt->setInt32 (++index, int32(_resolvedBy.GetCounter()));
117
118 CharacterDatabase.ExecuteOrAppend(trans, stmt);
119}
120
122{
124 stmt->setUInt32(0, _id);
125 CharacterDatabase.Execute(stmt);
126}
127
129{
131 data << uint32(_id);
132 data << _message;
133 data << uint8(_needMoreHelp);
134 data << GetAge(_lastModifiedTime);
135 if (GmTicket* ticket = sTicketMgr->GetOldestOpenTicket())
136 data << GetAge(ticket->GetLastModifiedTime());
137 else
138 data << float(0);
139
140 // I am not sure how blizzlike this is, and we don't really have a way to find out
141 data << GetAge(sTicketMgr->GetLastChange());
142
143 data << uint8(std::min(_escalatedStatus, TICKET_IN_ESCALATION_QUEUE)); // escalated data
144 data << uint8(_viewed ? GMTICKET_OPENEDBYGM_STATUS_OPENED : GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED); // whether or not it has been viewed
145}
146
148{
150 data << uint32(1); // responseID
151 data << uint32(_id); // ticketID
152 data << _message.c_str();
153
154 size_t len = _response.size();
155 char const* s = _response.c_str();
156
157 for (int i = 0; i < 4; i++)
158 {
159 if (len)
160 {
161 size_t writeLen = std::min<size_t>(len, 3999);
162 data.append(s, writeLen);
163
164 len -= writeLen;
165 s += writeLen;
166 }
167
168 data << uint8(0);
169 }
170
171 session->SendPacket(&data);
172}
173
174std::string GmTicket::FormatMessageString(ChatHandler& handler, bool detailed) const
175{
176 time_t curTime = GameTime::GetGameTime();
177
178 std::stringstream ss;
183
184 std::string name;
185 if (sCharacterCache->GetCharacterNameByGuid(_assignedTo, name))
186 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
187
188 if (detailed)
189 {
191 if (!_comment.empty())
193 if (!_response.empty())
195 }
196 return ss.str();
197}
198
199std::string GmTicket::FormatMessageString(ChatHandler& handler, char const* szClosedName, char const* szAssignedToName, char const* szUnassignedName, char const* szDeletedName, char const* szCompletedName) const
200{
201 std::stringstream ss;
204 if (szClosedName)
205 ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName);
206 if (szAssignedToName)
207 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName);
208 if (szUnassignedName)
209 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName);
210 if (szDeletedName)
211 ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName);
212 if (szCompletedName)
213 ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName);
214 return ss.str();
215}
216
217void GmTicket::SetMessage(std::string const& message)
218{
219 _message = message;
221}
222
224{
226 switch (_escalatedStatus)
227 {
232 default:
233 break;
234 }
235}
236
237void GmTicket::SetPosition(uint32 mapId, float x, float y, float z)
238{
239 _mapId = mapId;
240 _posX = x;
241 _posY = y;
242 _posZ = z;
243}
244
245void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp)
246{
247 _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default)
248 _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket"
249}
250
251void GmTicket::TeleportTo(Player* player) const
252{
253 player->TeleportTo(_mapId, _posX, _posY, _posZ, 0.0f, 0);
254}
255
256void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log)
257{
258 std::stringstream ss(log);
259 std::stringstream newss;
260 std::string line;
261 while (std::getline(ss, line) && !time.empty())
262 {
263 newss << secsToTimeString(time.front()) << ": " << line << "\n";
264 time.pop_front();
265 }
266
267 _chatLog = newss.str();
268}
269
271// Ticket manager
272TicketMgr::TicketMgr() : _status(true), _lastTicketId(0), _lastSurveyId(0), _openTicketCount(0),
273 _lastChange(GameTime::GetGameTime()) { }
274
276{
277 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
278 delete itr->second;
279}
280
282{
283 SetStatus(sWorld->getBoolConfig(CONFIG_ALLOW_TICKETS));
284}
285
287{
288 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end();)
289 {
290 if (itr->second->IsClosed())
291 {
292 uint32 ticketId = itr->second->GetId();
293 ++itr;
294 sTicketMgr->RemoveTicket(ticketId);
295 }
296 else
297 ++itr;
298 }
299
300 _lastTicketId = 0;
301
303
304 CharacterDatabase.Execute(stmt);
305}
306
308{
309 static TicketMgr instance;
310 return &instance;
311}
312
314{
315 uint32 oldMSTime = getMSTime();
316
317 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
318 delete itr->second;
319 _ticketList.clear();
320
321 _lastTicketId = 0;
323
325 PreparedQueryResult result = CharacterDatabase.Query(stmt);
326 if (!result)
327 {
328 TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_ticket` is empty!");
329
330 return;
331 }
332
333 uint32 count = 0;
334 do
335 {
336 Field* fields = result->Fetch();
337 GmTicket* ticket = new GmTicket();
338 if (!ticket->LoadFromDB(fields))
339 {
340 delete ticket;
341 continue;
342 }
343 if (!ticket->IsClosed())
345
346 // Update max ticket id if necessary
347 uint32 id = ticket->GetId();
348 if (_lastTicketId < id)
349 _lastTicketId = id;
350
351 _ticketList[id] = ticket;
352 ++count;
353 } while (result->NextRow());
354
355 TC_LOG_INFO("server.loading", ">> Loaded {} GM tickets in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
356
357}
358
360{
361 // we don't actually load anything into memory here as there's no reason to
362 _lastSurveyId = 0;
363
364 uint32 oldMSTime = getMSTime();
365 if (QueryResult result = CharacterDatabase.Query("SELECT MAX(surveyId) FROM gm_survey"))
366 _lastSurveyId = (*result)[0].GetUInt32();
367
368 TC_LOG_INFO("server.loading", ">> Loaded GM Survey count from database in {} ms", GetMSTimeDiffToNow(oldMSTime));
369
370}
371
373{
374 _ticketList[ticket->GetId()] = ticket;
375 if (!ticket->IsClosed())
378 ticket->SaveToDB(trans);
379}
380
382{
383 if (GmTicket* ticket = GetTicket(ticketId))
384 {
386 ticket->SetClosedBy(source);
387 if (!source.IsEmpty())
389 ticket->SaveToDB(trans);
390 }
391}
392
394{
395 if (GmTicket* ticket = GetTicket(ticketId))
396 {
398 ticket->SetClosedBy(source);
399 ticket->SetResolvedBy(source);
400 if (!source.IsEmpty())
402 ticket->SaveToDB(trans);
403 }
404}
405
407{
408 if (GmTicket* ticket = GetTicket(ticketId))
409 {
410 ticket->DeleteFromDB();
411 _ticketList.erase(ticketId);
412 delete ticket;
413 }
414}
415
420
421void TicketMgr::ShowList(ChatHandler& handler, bool onlineOnly) const
422{
424 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
425 if (!itr->second->IsClosed() && !itr->second->IsCompleted())
426 if (!onlineOnly || itr->second->GetPlayer())
427 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
428}
429
431{
433 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
434 if (itr->second->IsClosed())
435 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
436}
437
439{
441 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
442 if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE)
443 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
444}
445
446void TicketMgr::SendTicket(WorldSession* session, GmTicket* ticket) const
447{
448 WorldPacket data(SMSG_GMTICKET_GETTICKET, (4 + 4 + 1 + 4 + 4 + 4 + 1 + 1));
449
450 if (ticket)
451 ticket->WritePacket(data);
452 else
454
455 session->SendPacket(&data);
456}
457
459{
460 std::string name;
461 // save queries if ticket is not assigned
462 if (!_assignedTo.IsEmpty())
463 sCharacterCache->GetCharacterNameByGuid(_assignedTo, name);
464
465 return name;
466}
#define sCharacterCache
@ CHAR_DEL_ALL_GM_TICKETS
@ CHAR_SEL_GM_TICKETS
@ CHAR_REP_GM_TICKET
@ CHAR_DEL_GM_TICKET
@ DAY
Definition Common.h:31
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint32_t uint32
Definition Define.h:133
@ LANG_COMMAND_TICKETSHOWONLINELIST
Definition Language.h:1035
@ LANG_COMMAND_TICKETSHOWESCALATEDLIST
Definition Language.h:1051
@ LANG_COMMAND_TICKETLISTGUID
Definition Language.h:1042
@ LANG_COMMAND_TICKETSHOWLIST
Definition Language.h:1034
@ LANG_COMMAND_TICKETCLOSED
Definition Language.h:1028
@ LANG_COMMAND_TICKETDELETED
Definition Language.h:1029
@ LANG_COMMAND_TICKETLISTCOMMENT
Definition Language.h:1048
@ LANG_COMMAND_TICKETLISTAGE
Definition Language.h:1044
@ LANG_COMMAND_TICKETCOMPLETED
Definition Language.h:1055
@ LANG_COMMAND_TICKETLISTRESPONSE
Definition Language.h:1054
@ LANG_COMMAND_TICKETLISTASSIGNEDTO
Definition Language.h:1045
@ LANG_COMMAND_TICKETLISTAGECREATE
Definition Language.h:1050
@ LANG_COMMAND_TICKETLISTUNASSIGNED
Definition Language.h:1046
@ LANG_COMMAND_TICKETSHOWCLOSEDLIST
Definition Language.h:1036
@ LANG_COMMAND_TICKETLISTMESSAGE
Definition Language.h:1047
@ LANG_COMMAND_TICKETLISTNAME
Definition Language.h:1043
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
float GetAge(uint64 t)
Definition TicketMgr.cpp:33
#define sTicketMgr
Definition TicketMgr.h:248
TicketType
Definition TicketMgr.h:84
@ TICKET_TYPE_OPEN
Definition TicketMgr.h:85
GMTicketEscalationStatus
Definition TicketMgr.h:59
@ TICKET_ESCALATED_ASSIGNED
Definition TicketMgr.h:63
@ TICKET_IN_ESCALATION_QUEUE
Definition TicketMgr.h:62
@ TICKET_UNASSIGNED
Definition TicketMgr.h:60
@ TICKET_ASSIGNED
Definition TicketMgr.h:61
@ GMTICKET_STATUS_DEFAULT
Definition TicketMgr.h:40
@ GMTICKET_STATUS_HASTEXT
Definition TicketMgr.h:39
@ GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED
Definition TicketMgr.h:69
@ GMTICKET_OPENEDBYGM_STATUS_OPENED
Definition TicketMgr.h:70
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hoursOnly)
Definition Util.cpp:115
void append(T value)
Definition ByteBuffer.h:129
size_t size() const
Definition ByteBuffer.h:409
static std::string PGetParseString(std::string_view fmt, Args &&... args)
Definition Chat.h:81
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition Chat.cpp:101
Class used to access individual fields of database query result.
Definition Field.h:92
std::string GetString() const
Definition Field.cpp:125
uint16 GetUInt16() const
Definition Field.cpp:45
float GetFloat() const
Definition Field.cpp:93
bool GetBool() const
Definition Field.h:100
uint32 GetUInt32() const
Definition Field.cpp:61
ObjectGuid _playerGuid
Definition TicketMgr.h:152
bool _viewed
Definition TicketMgr.h:167
void DeleteFromDB()
ObjectGuid _resolvedBy
Definition TicketMgr.h:162
void SetUnassigned()
bool IsClosed() const
Definition TicketMgr.h:97
TicketType _type
Definition TicketMgr.h:151
float _posZ
Definition TicketMgr.h:156
std::string _chatLog
Definition TicketMgr.h:171
bool _completed
Definition TicketMgr.h:165
Player * GetPlayer() const
Definition TicketMgr.cpp:54
GMTicketEscalationStatus _escalatedStatus
Definition TicketMgr.h:166
std::string _message
Definition TicketMgr.h:158
void SetPosition(uint32 mapId, float x, float y, float z)
ObjectGuid _assignedTo
Definition TicketMgr.h:163
void WritePacket(WorldPacket &data) const
ObjectGuid _closedBy
Definition TicketMgr.h:161
void SetMessage(std::string const &message)
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition TicketMgr.cpp:91
void SetGmAction(uint32 needResponse, bool needMoreHelp)
std::string _response
Definition TicketMgr.h:170
std::string _comment
Definition TicketMgr.h:164
void TeleportTo(Player *player) const
bool _needResponse
Definition TicketMgr.h:168
bool _needMoreHelp
Definition TicketMgr.h:169
float _posY
Definition TicketMgr.h:155
uint16 _mapId
Definition TicketMgr.h:157
std::string _playerName
Definition TicketMgr.h:153
bool LoadFromDB(Field *fields)
Definition TicketMgr.cpp:64
uint32 _id
Definition TicketMgr.h:150
uint32 GetId() const
Definition TicketMgr.h:104
float _posX
Definition TicketMgr.h:154
void SendResponse(WorldSession *session) const
std::string FormatMessageString(ChatHandler &handler, bool detailed=false) const
uint64 _createTime
Definition TicketMgr.h:159
void SetChatLog(std::list< uint32 > time, std::string const &log)
std::string GetAssignedToName() const
uint64 _lastModifiedTime
Definition TicketMgr.h:160
Player * GetAssignedPlayer() const
Definition TicketMgr.cpp:59
LowType GetCounter() const
Definition ObjectGuid.h:156
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
void Clear()
Definition ObjectGuid.h:150
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1524
void setUInt16(uint8 index, uint16 value)
void setUInt32(uint8 index, uint32 value)
void setBool(uint8 index, bool value)
void setFloat(uint8 index, float value)
void setInt32(uint8 index, int32 value)
void setUInt8(uint8 index, uint8 value)
void setString(uint8 index, std::string const &value)
void RemoveTicket(uint32 ticketId)
uint32 _lastTicketId
Definition TicketMgr.h:242
void CloseTicket(uint32 ticketId, ObjectGuid source)
void LoadTickets()
GmTicketList _ticketList
Definition TicketMgr.h:239
void ShowClosedList(ChatHandler &handler) const
void LoadSurveys()
void AddTicket(GmTicket *ticket)
void SetStatus(bool status)
Definition TicketMgr.h:220
uint32 _openTicketCount
Definition TicketMgr.h:244
uint32 _lastSurveyId
Definition TicketMgr.h:243
void ResetTickets()
void ShowEscalatedList(ChatHandler &handler) const
void ResolveAndCloseTicket(uint32 ticketId, ObjectGuid source)
void UpdateLastChange()
GmTicket * GetTicket(uint32 ticketId)
Definition TicketMgr.h:187
uint64 _lastChange
Definition TicketMgr.h:245
void Initialize()
static TicketMgr * instance()
void SendTicket(WorldSession *session, GmTicket *ticket) const
void ShowList(ChatHandler &handler, bool onlineOnly) const
std::string const & GetName() const
Definition Object.h:382
Player session in the World.
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
@ SMSG_GMRESPONSE_RECEIVED
Definition Opcodes.h:1292
@ SMSG_GMTICKET_GETTICKET
Definition Opcodes.h:559
#define sWorld
Definition World.h:900
@ CONFIG_ALLOW_TICKETS
Definition World.h:146
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * FindPlayer(ObjectGuid const &)