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 "TicketPackets.h"
30#include "World.h"
31#include "WorldPacket.h"
32#include "WorldSession.h"
33
34inline float GetAge(uint64 t) { return float(GameTime::GetGameTime() - t) / float(DAY); }
35
37// GM ticket
38GmTicket::GmTicket() : _id(0), _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
39 _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
40 _needResponse(false), _needMoreHelp(false) { }
41
42GmTicket::GmTicket(Player* player) : _type(TICKET_TYPE_OPEN), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(GameTime::GetGameTime()), _lastModifiedTime(GameTime::GetGameTime()),
43 _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
44 _needResponse(false), _needMoreHelp(false)
45{
46 _id = sTicketMgr->GenerateTicketId();
47 _playerName = player->GetName();
48 _playerGuid = player->GetGUID();
49}
50
54
59
64
66{
67 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
68 // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp
69 uint8 index = 0;
70 _id = fields[ index].GetUInt32();
71 _type = TicketType(fields[++index].GetUInt8());
72 _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt32());
73 _playerName = fields[++index].GetString();
74 _message = fields[++index].GetString();
75 _createTime = fields[++index].GetUInt32();
76 _mapId = fields[++index].GetUInt16();
77 _posX = fields[++index].GetFloat();
78 _posY = fields[++index].GetFloat();
79 _posZ = fields[++index].GetFloat();
80 _lastModifiedTime = fields[++index].GetUInt32();
81 _closedBy = fields[++index].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[index].GetUInt32()) : ObjectGuid::Empty;
82 _assignedTo = fields[++index].GetUInt32() ? ObjectGuid::Create<HighGuid::Player>(fields[index].GetUInt32()) : ObjectGuid::Empty;
83 _comment = fields[++index].GetString();
84 _response = fields[++index].GetString();
85 _completed = fields[++index].GetBool();
86 _escalatedStatus = GMTicketEscalationStatus(fields[++index].GetUInt8());
87 _viewed = fields[++index].GetBool();
88 _needMoreHelp = fields[++index].GetBool();
89 return true;
90}
91
93{
94 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
95 // id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
96 uint8 index = 0;
98 stmt->setUInt32( index, _id);
99 stmt->setUInt8 (++index, uint8(_type));
100 stmt->setUInt32(++index, _playerGuid.GetCounter());
101 stmt->setString(++index, _playerName);
102 stmt->setString(++index, _message);
103 stmt->setUInt32(++index, uint32(_createTime));
104 stmt->setUInt16(++index, _mapId);
105 stmt->setFloat (++index, _posX);
106 stmt->setFloat (++index, _posY);
107 stmt->setFloat (++index, _posZ);
108 stmt->setUInt32(++index, uint32(_lastModifiedTime));
109 stmt->setUInt32(++index, _closedBy.GetCounter());
110 stmt->setUInt32(++index, _assignedTo.GetCounter());
111 stmt->setString(++index, _comment);
112 stmt->setString(++index, _response);
113 stmt->setBool (++index, _completed);
114 stmt->setUInt8 (++index, uint8(_escalatedStatus));
115 stmt->setBool (++index, _viewed);
116 stmt->setBool (++index, _needMoreHelp);
117 stmt->setInt32 (++index, int32(_resolvedBy.GetCounter()));
118
119 CharacterDatabase.ExecuteOrAppend(trans, stmt);
120}
121
123{
125 stmt->setUInt32(0, _id);
126 CharacterDatabase.Execute(stmt);
127}
128
130{
132 data << uint32(1); // responseID
133 data << uint32(_id); // ticketID
134 data << _message.c_str();
135
136 size_t len = _response.size();
137 char const* s = _response.c_str();
138
139 for (int i = 0; i < 4; i++)
140 {
141 if (len)
142 {
143 size_t writeLen = std::min<size_t>(len, 3999);
144 data.append(s, writeLen);
145
146 len -= writeLen;
147 s += writeLen;
148 }
149
150 data << uint8(0);
151 }
152
153 session->SendPacket(&data);
154}
155
156std::string GmTicket::FormatMessageString(ChatHandler& handler, bool detailed) const
157{
158 time_t curTime = GameTime::GetGameTime();
159
160 std::stringstream ss;
165
166 std::string name;
167 if (sCharacterCache->GetCharacterNameByGuid(_assignedTo, name))
168 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
169
170 if (detailed)
171 {
173 if (!_comment.empty())
175 if (!_response.empty())
177 }
178 return ss.str();
179}
180
181std::string GmTicket::FormatMessageString(ChatHandler& handler, char const* szClosedName, char const* szAssignedToName, char const* szUnassignedName, char const* szDeletedName, char const* szCompletedName) const
182{
183 std::stringstream ss;
186 if (szClosedName)
187 ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName);
188 if (szAssignedToName)
189 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName);
190 if (szUnassignedName)
191 ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName);
192 if (szDeletedName)
193 ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName);
194 if (szCompletedName)
195 ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName);
196 return ss.str();
197}
198
199void GmTicket::SetMessage(std::string const& message)
200{
201 _message = message;
203}
204
206{
208 switch (_escalatedStatus)
209 {
214 default:
215 break;
216 }
217}
218
219void GmTicket::SetPosition(uint32 mapId, float x, float y, float z)
220{
221 _mapId = mapId;
222 _posX = x;
223 _posY = y;
224 _posZ = z;
225}
226
227void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp)
228{
229 _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default)
230 _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket"
231}
232
233void GmTicket::TeleportTo(Player* player) const
234{
235 player->TeleportTo(_mapId, _posX, _posY, _posZ, 0.0f, 0);
236}
237
238void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log)
239{
240 std::stringstream ss(log);
241 std::stringstream newss;
242 std::string line;
243 while (std::getline(ss, line) && !time.empty())
244 {
245 newss << secsToTimeString(time.front()) << ": " << line << "\n";
246 time.pop_front();
247 }
248
249 _chatLog = newss.str();
250}
251
253// Ticket manager
254TicketMgr::TicketMgr() : _status(true), _lastTicketId(0), _lastSurveyId(0), _openTicketCount(0),
255 _lastChange(GameTime::GetGameTime()) { }
256
258{
259 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
260 delete itr->second;
261}
262
264{
265 SetStatus(sWorld->getBoolConfig(CONFIG_ALLOW_TICKETS));
266}
267
269{
270 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end();)
271 {
272 if (itr->second->IsClosed())
273 {
274 uint32 ticketId = itr->second->GetId();
275 ++itr;
276 sTicketMgr->RemoveTicket(ticketId);
277 }
278 else
279 ++itr;
280 }
281
282 _lastTicketId = 0;
283
285
286 CharacterDatabase.Execute(stmt);
287}
288
290{
291 static TicketMgr instance;
292 return &instance;
293}
294
296{
297 uint32 oldMSTime = getMSTime();
298
299 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
300 delete itr->second;
301 _ticketList.clear();
302
303 _lastTicketId = 0;
305
307 PreparedQueryResult result = CharacterDatabase.Query(stmt);
308 if (!result)
309 {
310 TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_ticket` is empty!");
311
312 return;
313 }
314
315 uint32 count = 0;
316 do
317 {
318 Field* fields = result->Fetch();
319 GmTicket* ticket = new GmTicket();
320 if (!ticket->LoadFromDB(fields))
321 {
322 delete ticket;
323 continue;
324 }
325 if (!ticket->IsClosed())
327
328 // Update max ticket id if necessary
329 uint32 id = ticket->GetId();
330 if (_lastTicketId < id)
331 _lastTicketId = id;
332
333 _ticketList[id] = ticket;
334 ++count;
335 } while (result->NextRow());
336
337 TC_LOG_INFO("server.loading", ">> Loaded {} GM tickets in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
338
339}
340
342{
343 // we don't actually load anything into memory here as there's no reason to
344 _lastSurveyId = 0;
345
346 uint32 oldMSTime = getMSTime();
347 if (QueryResult result = CharacterDatabase.Query("SELECT MAX(surveyId) FROM gm_survey"))
348 _lastSurveyId = (*result)[0].GetUInt32();
349
350 TC_LOG_INFO("server.loading", ">> Loaded GM Survey count from database in {} ms", GetMSTimeDiffToNow(oldMSTime));
351
352}
353
355{
356 _ticketList[ticket->GetId()] = ticket;
357 if (!ticket->IsClosed())
360 ticket->SaveToDB(trans);
361}
362
364{
365 if (GmTicket* ticket = GetTicket(ticketId))
366 {
368 ticket->SetClosedBy(source);
369 if (!source.IsEmpty())
371 ticket->SaveToDB(trans);
372 }
373}
374
376{
377 if (GmTicket* ticket = GetTicket(ticketId))
378 {
380 ticket->SetClosedBy(source);
381 ticket->SetResolvedBy(source);
382 if (!source.IsEmpty())
384 ticket->SaveToDB(trans);
385 }
386}
387
389{
390 if (GmTicket* ticket = GetTicket(ticketId))
391 {
392 ticket->DeleteFromDB();
393 _ticketList.erase(ticketId);
394 delete ticket;
395 }
396}
397
402
403void TicketMgr::ShowList(ChatHandler& handler, bool onlineOnly) const
404{
406 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
407 if (!itr->second->IsClosed() && !itr->second->IsCompleted())
408 if (!onlineOnly || itr->second->GetPlayer())
409 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
410}
411
413{
415 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
416 if (itr->second->IsClosed())
417 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
418}
419
421{
423 for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
424 if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE)
425 handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
426}
427
428void TicketMgr::SendTicket(WorldSession* session, GmTicket* ticket) const
429{
431
432 if (ticket)
433 {
435
436 WorldPackets::Ticket::GMTicketInfo& ticketInfo = response.Info;
437 ticketInfo.TicketID = ticket->GetId();
438 ticketInfo.TicketDescription = ticket->GetMessage();
439 ticketInfo.Category = ticket->GetNeedMoreHelp();
440 ticketInfo.TicketOpenTime = GetAge(ticket->GetLastModifiedTime());
441 if (GmTicket const* oldestTicket = sTicketMgr->GetOldestOpenTicket())
442 ticketInfo.OldestTicketTime = GetAge(oldestTicket->GetLastModifiedTime());
443
444 ticketInfo.UpdateTime = GetAge(sTicketMgr->GetLastChange());
445 ticketInfo.AssignedToGM = std::min(ticket->GetEscalatedStatus(), TICKET_IN_ESCALATION_QUEUE);
447 }
448 else
450
451 session->SendPacket(response.Write());
452}
453
455{
456 std::string name;
457 // save queries if ticket is not assigned
458 if (!_assignedTo.IsEmpty())
459 sCharacterCache->GetCharacterNameByGuid(_assignedTo, name);
460
461 return name;
462}
#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:34
#define sTicketMgr
Definition TicketMgr.h:250
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:133
size_t size() const
Definition ByteBuffer.h:413
static std::string PGetParseString(std::string_view fmt, Args &&... args)
Definition Chat.h:73
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition Chat.cpp:102
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:154
std::string const & GetMessage() const
Definition TicketMgr.h:108
bool _viewed
Definition TicketMgr.h:169
void DeleteFromDB()
ObjectGuid _resolvedBy
Definition TicketMgr.h:164
bool GetNeedMoreHelp() const
Definition TicketMgr.h:109
void SetUnassigned()
bool IsClosed() const
Definition TicketMgr.h:97
TicketType _type
Definition TicketMgr.h:153
float _posZ
Definition TicketMgr.h:158
std::string _chatLog
Definition TicketMgr.h:173
bool _completed
Definition TicketMgr.h:167
Player * GetPlayer() const
Definition TicketMgr.cpp:55
GMTicketEscalationStatus _escalatedStatus
Definition TicketMgr.h:168
std::string _message
Definition TicketMgr.h:160
void SetPosition(uint32 mapId, float x, float y, float z)
ObjectGuid _assignedTo
Definition TicketMgr.h:165
ObjectGuid _closedBy
Definition TicketMgr.h:163
void SetMessage(std::string const &message)
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition TicketMgr.cpp:92
void SetGmAction(uint32 needResponse, bool needMoreHelp)
std::string _response
Definition TicketMgr.h:172
uint64 GetLastModifiedTime() const
Definition TicketMgr.h:113
std::string _comment
Definition TicketMgr.h:166
void TeleportTo(Player *player) const
bool _needResponse
Definition TicketMgr.h:170
bool _needMoreHelp
Definition TicketMgr.h:171
float _posY
Definition TicketMgr.h:157
uint16 _mapId
Definition TicketMgr.h:159
std::string _playerName
Definition TicketMgr.h:155
bool LoadFromDB(Field *fields)
Definition TicketMgr.cpp:65
uint32 _id
Definition TicketMgr.h:152
uint32 GetId() const
Definition TicketMgr.h:105
float _posX
Definition TicketMgr.h:156
void SendResponse(WorldSession *session) const
std::string FormatMessageString(ChatHandler &handler, bool detailed=false) const
uint64 _createTime
Definition TicketMgr.h:161
void SetChatLog(std::list< uint32 > time, std::string const &log)
std::string GetAssignedToName() const
uint64 _lastModifiedTime
Definition TicketMgr.h:162
Player * GetAssignedPlayer() const
Definition TicketMgr.cpp:60
GMTicketEscalationStatus GetEscalatedStatus() const
Definition TicketMgr.h:114
bool IsViewed() const
Definition TicketMgr.h:103
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:1539
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:244
void CloseTicket(uint32 ticketId, ObjectGuid source)
void LoadTickets()
GmTicketList _ticketList
Definition TicketMgr.h:241
void ShowClosedList(ChatHandler &handler) const
void LoadSurveys()
void AddTicket(GmTicket *ticket)
void SetStatus(bool status)
Definition TicketMgr.h:222
uint32 _openTicketCount
Definition TicketMgr.h:246
uint32 _lastSurveyId
Definition TicketMgr.h:245
void ResetTickets()
void ShowEscalatedList(ChatHandler &handler) const
void ResolveAndCloseTicket(uint32 ticketId, ObjectGuid source)
void UpdateLastChange()
GmTicket * GetTicket(uint32 ticketId)
Definition TicketMgr.h:189
uint64 _lastChange
Definition TicketMgr.h:247
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:384
Player session in the World.
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
@ SMSG_GMRESPONSE_RECEIVED
Definition Opcodes.h:1292
#define sWorld
Definition World.h:901
@ CONFIG_ALLOW_TICKETS
Definition World.h:146
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * FindPlayer(ObjectGuid const &)