aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorCarbenium <keresztesschmidt@gmail.com>2015-02-08 01:07:00 +0100
committerCarbenium <keresztesschmidt@gmail.com>2015-03-10 21:09:21 +0100
commit37a14bc2d5066bdcdc24331c6718ccf54fb1afa5 (patch)
treea8514c64ae0e5184f20a810d36043d03ab4feac1 /src/server/game
parentc8944d73b32697456b8baeaa72f98378044d3800 (diff)
Core/Support: Update the support/ticket system to 6.x
Core/Mail: fix a logic error introduced in 829e11b6623f967672143d79cd8d31772f54866d
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Accounts/RBAC.h37
-rw-r--r--src/server/game/CMakeLists.txt6
-rw-r--r--src/server/game/Entities/Player/Player.cpp15
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp18
-rw-r--r--src/server/game/Handlers/TicketHandler.cpp230
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Server/Packets/LFGPackets.cpp28
-rw-r--r--src/server/game/Server/Packets/LFGPackets.h39
-rw-r--r--src/server/game/Server/Packets/SystemPackets.cpp14
-rw-r--r--src/server/game/Server/Packets/SystemPackets.h12
-rw-r--r--src/server/game/Server/Packets/TicketPackets.cpp291
-rw-r--r--src/server/game/Server/Packets/TicketPackets.h235
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp41
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h36
-rw-r--r--src/server/game/Server/WorldSession.h24
-rw-r--r--src/server/game/Support/SupportMgr.cpp1088
-rw-r--r--src/server/game/Support/SupportMgr.h416
-rw-r--r--src/server/game/Tickets/TicketMgr.cpp410
-rw-r--r--src/server/game/Tickets/TicketMgr.h256
-rw-r--r--src/server/game/World/World.cpp40
-rw-r--r--src/server/game/World/World.h8
21 files changed, 2350 insertions, 897 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 3f5a21f2888..e700a8b1708 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -554,7 +554,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER = 647,
RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE = 648,
RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER = 649,
- RBAC_PERM_COMMAND_RELOAD_GM_TICKETS = 650,
+ RBAC_PERM_COMMAND_RELOAD_SUPPORT_SYSTEM = 650,
RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU = 651,
RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION = 652,
RBAC_PERM_COMMAND_RELOAD_ITEM_ENCHANTMENT_TEMPLATE = 653,
@@ -703,6 +703,41 @@ enum RBACPermissions
RBAC_PERM_COMMAND_INSTANCE_GET_BOSS_STATE = 796,
RBAC_PERM_COMMAND_PVPSTATS = 797,
RBAC_PERM_COMMAND_MODIFY_XP = 798,
+ RBAC_PERM_COMMAND_GO_BUG_TICKET = 799,
+ RBAC_PERM_COMMAND_GO_COMPLAINT_TICKET = 800,
+ RBAC_PERM_COMMAND_GO_SUGGESTION_TICKET = 801,
+ RBAC_PERM_COMMAND_TICKET_BUG = 802,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT = 803,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION = 804,
+ RBAC_PERM_COMMAND_TICKET_BUG_ASSIGN = 805,
+ RBAC_PERM_COMMAND_TICKET_BUG_CLOSE = 806,
+ RBAC_PERM_COMMAND_TICKET_BUG_CLOSEDLIST = 807,
+ RBAC_PERM_COMMAND_TICKET_BUG_COMMENT = 808,
+ RBAC_PERM_COMMAND_TICKET_BUG_DELETE = 809,
+ RBAC_PERM_COMMAND_TICKET_BUG_LIST = 810,
+ RBAC_PERM_COMMAND_TICKET_BUG_UNASSIGN = 811,
+ RBAC_PERM_COMMAND_TICKET_BUG_VIEW = 812,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_ASSIGN = 813,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSE = 814,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_CLOSEDLIST = 815,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_COMMENT = 816,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_DELETE = 817,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_LIST = 818,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_UNASSIGN = 819,
+ RBAC_PERM_COMMAND_TICKET_COMPLAINT_VIEW = 820,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_ASSIGN = 821,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSE = 822,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_CLOSEDLIST = 823,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_COMMENT = 824,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_DELETE = 825,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_LIST = 826,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_UNASSIGN = 827,
+ RBAC_PERM_COMMAND_TICKET_SUGGESTION_VIEW = 828,
+ RBAC_PERM_COMMAND_TICKET_RESET_ALL = 829,
+ RBAC_PERM_COMMAND_TICKET_RESET_GM = 830,
+ RBAC_PERM_COMMAND_TICKET_RESET_BUG = 831,
+ RBAC_PERM_COMMAND_TICKET_RESET_COMPLAINT = 832,
+ RBAC_PERM_COMMAND_TICKET_RESET_SUGGESTION = 833,
// custom permissions 1000+
RBAC_PERM_MAX
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index 2773178da08..18c710c2a20 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -43,9 +43,9 @@ file(GLOB_RECURSE sources_Scripting Scripting/*.cpp Scripting/*.h)
file(GLOB_RECURSE sources_Server Server/*.cpp Server/*.h)
file(GLOB_RECURSE sources_Skills Skills/*.cpp Skills/*.h)
file(GLOB_RECURSE sources_Spells Spells/*.cpp Spells/*.h)
+file(GLOB_RECURSE sources_Support Support/*.cpp Support/*.h)
file(GLOB_RECURSE sources_Texts Texts/*.cpp Texts/*.h)
file(GLOB_RECURSE sources_Tools Tools/*.cpp Tools/*.h)
-file(GLOB_RECURSE sources_Tickets Tickets/*.cpp Tickets/*.h)
file(GLOB_RECURSE sources_Warden Warden/*.cpp Warden/*.h)
file(GLOB_RECURSE sources_Weather Weather/*.cpp Weather/*.h)
file(GLOB_RECURSE sources_World World/*.cpp World/*.h)
@@ -94,9 +94,9 @@ set(game_STAT_SRCS
${sources_Server}
${sources_Skills}
${sources_Spells}
+ ${sources_Support}
${sources_Texts}
${sources_Tools}
- ${sources_Tickets}
${sources_Warden}
${sources_Weather}
${sources_World}
@@ -198,9 +198,9 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Skills
${CMAKE_CURRENT_SOURCE_DIR}/Spells
${CMAKE_CURRENT_SOURCE_DIR}/Spells/Auras
+ ${CMAKE_CURRENT_SOURCE_DIR}/Support
${CMAKE_CURRENT_SOURCE_DIR}/Texts
${CMAKE_CURRENT_SOURCE_DIR}/Tools
- ${CMAKE_CURRENT_SOURCE_DIR}/Tickets
${CMAKE_CURRENT_SOURCE_DIR}/Warden
${CMAKE_CURRENT_SOURCE_DIR}/Warden/Modules
${CMAKE_CURRENT_SOURCE_DIR}/Weather
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a25111df730..b46783deffb 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3243,17 +3243,12 @@ void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResp
result.Command = mailAction;
result.ErrorCode = mailError;
- switch (mailError)
+ if (mailError == MAIL_ERR_EQUIP_ERROR)
+ result.BagResult = equipError;
+ else if (mailAction == MAIL_ITEM_TAKEN)
{
- case MAIL_ERR_EQUIP_ERROR:
- result.BagResult = equipError;
- break;
- case MAIL_ITEM_TAKEN:
- result.AttachID = item_guid;
- result.QtyInInventory = item_count;
- break;
- default:
- break;
+ result.AttachID = item_guid;
+ result.QtyInInventory = item_count;
}
GetSession()->SendPacket(result.Write());
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index ba6b064d2f3..7a63d38f4fa 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1096,14 +1096,20 @@ void WorldSession::SendFeatureSystemStatus()
features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened
features.EuropaTicketSystemStatus.HasValue = true;
- features.EuropaTicketSystemStatus.Value.ThrottleState.MaxTries = 5;
- features.EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds = 5;
- features.EuropaTicketSystemStatus.Value.ThrottleState.TryCount = 0;
- features.EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow = time(nullptr) - 5000;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.MaxTries = 10;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds = 60000;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.TryCount = 1;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow = 111111;
+ features.ComplaintStatus = 0;
+ features.TutorialsEnabled = true;
+ features.UnkBit90 = true;
/// END OF DUMMY VALUES
- features.EuropaTicketSystemStatus.Value.SubmitBugEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_BUG);
- features.EuropaTicketSystemStatus.Value.TicketSystemEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_TICKET);
+ features.EuropaTicketSystemStatus.Value.TicketsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED);
+ features.EuropaTicketSystemStatus.Value.BugsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED);
+ features.EuropaTicketSystemStatus.Value.ComplaintsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED);
+ features.EuropaTicketSystemStatus.Value.SuggestionsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED);
+
features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED);
features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED);
diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp
index 5b2e197ae7a..55bbe96f15c 100644
--- a/src/server/game/Handlers/TicketHandler.cpp
+++ b/src/server/game/Handlers/TicketHandler.cpp
@@ -22,17 +22,17 @@
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
-#include "TicketMgr.h"
+#include "SupportMgr.h"
#include "TicketPackets.h"
#include "Util.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData)
+void WorldSession::HandleGMTicketCreateOpcode(WorldPackets::Ticket::GMTicketCreate& packet)
{
// Don't accept tickets if the ticket queue is disabled. (Ticket UI is greyed out but not fully dependable)
- if (sTicketMgr->GetStatus() == GMTICKET_QUEUE_STATUS_DISABLED)
+ if (sSupportMgr->GetSupportSystemStatus() == GMTICKET_QUEUE_STATUS_DISABLED)
return;
if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ))
@@ -42,140 +42,101 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData)
}
GMTicketResponse response = GMTICKET_RESPONSE_CREATE_ERROR;
- GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID());
+ GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID());
if (ticket && ticket->IsCompleted())
- sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID());
+ sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID());
// Player must not have ticket
if (!ticket || ticket->IsClosed())
{
- uint32 mapId;
- float x, y, z;
- std::string message;
- uint32 needResponse;
- bool needMoreHelp;
- uint32 count;
- std::list<uint32> times;
- uint32 decompressedSize;
std::string chatLog;
- recvData >> mapId;
- recvData >> x >> y >> z;
- recvData >> message;
-
- recvData >> needResponse;
- recvData >> needMoreHelp;
-
- recvData >> count;
-
- for (uint32 i = 0; i < count; i++)
+ if (packet.DataLength > 0 && packet.ChatHistoryData.DecompressedSize < 0xFFFF)
{
- uint32 time;
- recvData >> time;
- times.push_back(time);
- }
-
- recvData >> decompressedSize;
-
- if (count && decompressedSize && decompressedSize < 0xFFFF)
- {
- uint32 pos = recvData.rpos();
ByteBuffer dest;
- dest.resize(decompressedSize);
+ dest.resize(size_t(packet.ChatHistoryData.DecompressedSize));
- uLongf realSize = decompressedSize;
- if (uncompress(dest.contents(), &realSize, recvData.contents() + pos, recvData.size() - pos) == Z_OK)
- {
+ uLongf realSize = packet.ChatHistoryData.DecompressedSize;
+
+ if (uncompress(dest.contents(), &realSize, packet.ChatHistoryData.Data.contents(), packet.ChatHistoryData.Data.size()) == Z_OK)
dest >> chatLog;
- }
else
{
TC_LOG_ERROR("network", "CMSG_GM_TICKET_CREATE possibly corrupt. Uncompression failed.");
- recvData.rfinish();
return;
}
-
- recvData.rfinish(); // Will still have compressed data in buffer.
}
ticket = new GmTicket(GetPlayer());
- ticket->SetPosition(mapId, x, y, z);
- ticket->SetMessage(message);
- ticket->SetGmAction(needResponse, needMoreHelp);
+ ticket->SetPosition(packet.Map, packet.Pos);
+ ticket->SetDescription(packet.Description);
+ ticket->SetGmAction(packet.NeedResponse, packet.NeedMoreHelp);
- if (!chatLog.empty())
- ticket->SetChatLog(times, chatLog);
+ //TODO: more reasearch needed
+ //if (!chatLog.empty())
+ //ticket->SetChatLog(times, chatLog);
- sTicketMgr->AddTicket(ticket);
- sTicketMgr->UpdateLastChange();
+ sSupportMgr->AddTicket(ticket);
+ sSupportMgr->UpdateLastChange();
sWorld->SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName().c_str(), ticket->GetId());
response = GMTICKET_RESPONSE_CREATE_SUCCESS;
}
-
- WorldPacket data(SMSG_GM_TICKET_UPDATE, 4);
- data << uint32(response);
- SendPacket(&data);
+ sSupportMgr->SendGmTicketUpdate(this, response);
}
-void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket& recvData)
+void WorldSession::HandleGMTicketUpdateTextOpcode(WorldPackets::Ticket::GMTicketUpdateText& packet)
{
- std::string message;
- recvData >> message;
-
GMTicketResponse response = GMTICKET_RESPONSE_UPDATE_ERROR;
- if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
+ if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID()))
{
SQLTransaction trans = SQLTransaction(NULL);
- ticket->SetMessage(message);
+ ticket->SetDescription(packet.Description);
ticket->SaveToDB(trans);
sWorld->SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName().c_str(), ticket->GetId());
response = GMTICKET_RESPONSE_UPDATE_SUCCESS;
}
-
- WorldPacket data(SMSG_GM_TICKET_UPDATE, 4);
- data << uint32(response);
- SendPacket(&data);
+ sSupportMgr->SendGmTicketUpdate(this, response);
}
-void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recvData*/)
+void WorldSession::HandleGMTicketDeleteOpcode(WorldPackets::Ticket::GMTicketDelete& /*packet*/)
{
- if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
+ if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID()))
{
- WorldPacket data(SMSG_GM_TICKET_UPDATE, 4);
- data << uint32(GMTICKET_RESPONSE_TICKET_DELETED);
- SendPacket(&data);
+ sSupportMgr->SendGmTicketUpdate(this, GMTICKET_RESPONSE_TICKET_DELETED);
sWorld->SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName().c_str(), ticket->GetId());
- sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID());
- sTicketMgr->SendTicket(this, NULL);
+ sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID());
+ sSupportMgr->SendGmTicket(this, NULL);
}
}
void WorldSession::HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& /*packet*/)
{
- // TODO: Implement GmCase and handle this packet correctly
+ // TODO: Implement GmCase and handle this packet properly
+ WorldPackets::Ticket::GMTicketCaseStatus status;
+ status.OldestTicketTime = time(nullptr);
+ SendPacket(status.Write());
}
void WorldSession::HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& /*packet*/)
{
SendQueryTimeResponse();
- if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
+ if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID()))
{
if (ticket->IsCompleted())
- // TODO: Update SMSG_GM_TICKET_RESPONSE
ticket->SendResponse(this);
else
- sTicketMgr->SendTicket(this, ticket);
+ sSupportMgr->SendGmTicket(this, ticket);
}
else
- sTicketMgr->SendTicket(this, NULL);
+ sSupportMgr->SendGmTicket(this, NULL);
}
void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& /*packet*/)
@@ -183,100 +144,93 @@ void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTick
// Note: This only disables the ticket UI at client side and is not fully reliable
// Note: This disables the whole customer support UI after trying to send a ticket in disabled state (MessageBox: "GM Help Tickets are currently unavaiable."). UI remains disabled until the character relogs.
WorldPackets::Ticket::GMTicketSystemStatus response;
- response.Status = sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED;
+ response.Status = sSupportMgr->GetSupportSystemStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED;
SendPacket(response.Write());
}
-void WorldSession::HandleGMSurveySubmit(WorldPacket& recvData)
+void WorldSession::HandleGMSurveySubmit(WorldPackets::Ticket::GMSurveySubmit& /*packet*/)
{
- uint32 nextSurveyID = sTicketMgr->GetNextSurveyID();
- // just put the survey into the database
- uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc
- recvData >> mainSurvey;
+ /*uint32 nextSurveyID = sSupportMgr->GetNextSurveyID();
std::unordered_set<uint32> surveyIds;
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- // sub_survey1, r1, comment1, sub_survey2, r2, comment2, sub_survey3, r3, comment3, sub_survey4, r4, comment4, sub_survey5, r5, comment5, sub_survey6, r6, comment6, sub_survey7, r7, comment7, sub_survey8, r8, comment8, sub_survey9, r9, comment9, sub_survey10, r10, comment10,
- for (uint8 i = 0; i < 15; i++)
+
+ for (auto const& q : packet.SurveyQuestion)
{
- uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc)
- recvData >> subSurveyId;
- if (!subSurveyId)
+ if (!q.QuestionID)
break;
- uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc
- recvData >> rank;
- std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)")
- recvData >> comment;
-
// make sure the same sub survey is not added to DB twice
- if (!surveyIds.insert(subSurveyId).second)
+ if (!surveyIds.insert(q.QuestionID).second)
continue;
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SUBSURVEY);
stmt->setUInt32(0, nextSurveyID);
- stmt->setUInt32(1, subSurveyId);
- stmt->setUInt32(2, rank);
- stmt->setString(3, comment);
+ stmt->setUInt32(1, q.QuestionID); // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc)
+ stmt->setUInt32(2, q.Answer); // probably some sort of ref to GMSurveyAnswers.dbc
+ stmt->setString(3, q.AnswerComment); // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)")
trans->Append(stmt);
}
- std::string comment; // just a guess
- recvData >> comment;
-
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SURVEY);
stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter());
stmt->setUInt32(1, nextSurveyID);
- stmt->setUInt32(2, mainSurvey);
- stmt->setString(3, comment);
-
+ stmt->setUInt32(2, packet.SurveyID); // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc
+ stmt->setString(3, packet.Comment);
trans->Append(stmt);
- CharacterDatabase.CommitTransaction(trans);
+ CharacterDatabase.CommitTransaction(trans);*/
}
-void WorldSession::HandleReportLag(WorldPacket& recvData)
+void WorldSession::HandleGMResponseResolve(WorldPackets::Ticket::GMTicketResponseResolve& /*packet*/)
{
- // just put the lag report into the database...
- // can't think of anything else to do with it
- uint32 lagType, mapId;
- recvData >> lagType;
- recvData >> mapId;
- float x, y, z;
- recvData >> x;
- recvData >> y;
- recvData >> z;
-
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LAG_REPORT);
- stmt->setUInt64(0, GetPlayer()->GetGUID().GetCounter());
- stmt->setUInt8 (1, lagType);
- stmt->setUInt16(2, mapId);
- stmt->setFloat (3, x);
- stmt->setFloat (4, y);
- stmt->setFloat (5, z);
- stmt->setUInt32(6, GetLatency());
- stmt->setUInt32(7, time(NULL));
- CharacterDatabase.Execute(stmt);
-}
-
-void WorldSession::HandleGMResponseResolve(WorldPacket& /*recvPacket*/)
-{
- // empty packet
- if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
+ if (GmTicket* ticket = sSupportMgr->GetGmTicketByPlayerGuid(GetPlayer()->GetGUID()))
{
- uint8 getSurvey = 0;
+ bool showSurvey = false;
if (float(rand_chance()) < sWorld->getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY))
- getSurvey = 1;
+ showSurvey = true;
- WorldPacket data(SMSG_GM_TICKET_STATUS_UPDATE, 4);
- data << uint8(getSurvey);
- SendPacket(&data);
+ WorldPackets::Ticket::GMTicketResolveResponse response;
+ response.ShowSurvey = showSurvey;
+ SendPacket(response.Write());
- WorldPacket data2(SMSG_GM_TICKET_UPDATE, 4);
- data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED);
- SendPacket(&data2);
+ sSupportMgr->SendGmTicketUpdate(this, GMTICKET_RESPONSE_TICKET_DELETED);
- sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID());
- sTicketMgr->SendTicket(this, NULL);
+ sSupportMgr->CloseTicket<GmTicket>(ticket->GetId(), GetPlayer()->GetGUID());
+ sSupportMgr->SendGmTicket(this, NULL);
}
}
+
+void WorldSession::HandleSupportTicketSubmitBug(WorldPackets::Ticket::SupportTicketSubmitBug& packet)
+{
+ BugTicket* ticket = new BugTicket(GetPlayer());
+ ticket->SetPosition(packet.Header.MapID, packet.Header.Position);
+ ticket->SetFacing(packet.Header.Facing);
+ ticket->SetNote(packet.Note);
+
+ sSupportMgr->AddTicket(ticket);
+}
+
+void WorldSession::HandleSupportTicketSubmitSuggestion(WorldPackets::Ticket::SupportTicketSubmitSuggestion& packet)
+{
+ SuggestionTicket* ticket = new SuggestionTicket(GetPlayer());
+ ticket->SetPosition(packet.Header.MapID, packet.Header.Position);
+ ticket->SetFacing(packet.Header.Facing);
+ ticket->SetNote(packet.Note);
+
+ sSupportMgr->AddTicket(ticket);
+}
+
+void WorldSession::HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet)
+{
+ ComplaintTicket* comp = new ComplaintTicket(GetPlayer());
+ comp->SetPosition(packet.Header.MapID, packet.Header.Position);
+ comp->SetFacing(packet.Header.Facing);
+ comp->SetChatLog(packet.ChatLog);
+ comp->SetTargetCharacterGuid(packet.TargetCharacterGUID);
+ comp->SetComplaintType(GMSupportComplaintType(packet.ComplaintType));
+ comp->SetNote(packet.Note);
+
+ sSupportMgr->AddTicket(comp);
+
+}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index ef4035469a9..446ee2606e1 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -985,7 +985,8 @@ enum TrinityStrings
LANG_ACCOUNT_ALREADY_LINKED = 1187,
LANG_ACCOUNT_BNET_UNLINKED = 1188,
LANG_ACCOUNT_BNET_NOT_LINKED = 1189,
- // Room for more level 3 1190-1199 not used
+ LANG_DISALLOW_TICKETS_CONFIG = 1190,
+ // Room for more level 3 1191-1199 not used
// Debug commands
LANG_CINEMATIC_NOT_EXIST = 1200,
diff --git a/src/server/game/Server/Packets/LFGPackets.cpp b/src/server/game/Server/Packets/LFGPackets.cpp
new file mode 100644
index 00000000000..4e7bc35b55a
--- /dev/null
+++ b/src/server/game/Server/Packets/LFGPackets.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 "LFGPackets.h"
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::LFG::RideTicket& ticket)
+{
+ data >> ticket.RequesterGuid;
+ data >> ticket.Id;
+ data >> ticket.Type;
+ data >> ticket.Time;
+
+ return data;
+}
diff --git a/src/server/game/Server/Packets/LFGPackets.h b/src/server/game/Server/Packets/LFGPackets.h
new file mode 100644
index 00000000000..e62cb47b41a
--- /dev/null
+++ b/src/server/game/Server/Packets/LFGPackets.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 LFGPackets_h__
+#define LFGPackets_h__
+
+#include "ObjectGuid.h"
+
+namespace WorldPackets
+{
+ namespace LFG
+ {
+ struct RideTicket
+ {
+ ObjectGuid RequesterGuid;
+ int32 Id = 0;
+ int32 Type = 0;
+ time_t Time = 0;
+ };
+ }
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::LFG::RideTicket& ticket);
+
+#endif // LFGPackets_h__
diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp
index 1a01c2d28c6..a88895fb35c 100644
--- a/src/server/game/Server/Packets/SystemPackets.cpp
+++ b/src/server/game/Server/Packets/SystemPackets.cpp
@@ -39,18 +39,20 @@ WorldPacket const* WorldPackets::System::FeatureSystemStatus::Write()
_worldPacket.WriteBit(SessionAlert.HasValue);
_worldPacket.WriteBit(RecruitAFriendSendingEnabled);
_worldPacket.WriteBit(CharUndeleteEnabled);
- _worldPacket.WriteBit(UnkBit21);
- _worldPacket.WriteBit(UnkBit22);
+ _worldPacket.WriteBit(RestrictedAccount);
+ _worldPacket.WriteBit(TutorialsEnabled);
_worldPacket.WriteBit(UnkBit90);
_worldPacket.WriteBit(TwitterEnabled);
_worldPacket.WriteBit(UnkBit61);
+ _worldPacket.FlushBits();
+
if (EuropaTicketSystemStatus.HasValue)
{
- _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit0);
- _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.UnkBit1);
- _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.TicketSystemEnabled);
- _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.SubmitBugEnabled);
+ _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.TicketsEnabled);
+ _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.BugsEnabled);
+ _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.ComplaintsEnabled);
+ _worldPacket.WriteBit(EuropaTicketSystemStatus.Value.SuggestionsEnabled);
_worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.MaxTries);
_worldPacket << uint32(EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds);
diff --git a/src/server/game/Server/Packets/SystemPackets.h b/src/server/game/Server/Packets/SystemPackets.h
index 897726575a4..d20d35649fb 100644
--- a/src/server/game/Server/Packets/SystemPackets.h
+++ b/src/server/game/Server/Packets/SystemPackets.h
@@ -37,10 +37,10 @@ namespace WorldPackets
struct EuropaTicketConfig
{
- bool UnkBit0 = false;
- bool UnkBit1 = false;
- bool TicketSystemEnabled = false;
- bool SubmitBugEnabled = false;
+ bool TicketsEnabled = false;
+ bool BugsEnabled = false;
+ bool ComplaintsEnabled = false;
+ bool SuggestionsEnabled = false;
SavedThrottleObjectState ThrottleState;
};
@@ -76,8 +76,8 @@ namespace WorldPackets
bool BpayStoreDisabledByParentalControls = false;
bool TwitterEnabled = false;
- bool UnkBit21 = false;
- bool UnkBit22 = false;
+ bool RestrictedAccount = false;
+ bool TutorialsEnabled = false;
bool UnkBit90 = false;
bool UnkBit61 = false;
};
diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp
index 8567cebd736..1a4d4d00c0a 100644
--- a/src/server/game/Server/Packets/TicketPackets.cpp
+++ b/src/server/game/Server/Packets/TicketPackets.cpp
@@ -15,8 +15,21 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "LFGPackets.h"
+#include "PacketUtilities.h"
#include "TicketPackets.h"
+using namespace WorldPackets;
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketHeader& header)
+{
+ data >> header.MapID;
+ data >> header.Position;
+ data >> header.Facing;
+
+ return data;
+}
+
WorldPacket const* WorldPackets::Ticket::GMTicketSystemStatus::Write()
{
_worldPacket << int32(Status);
@@ -80,3 +93,281 @@ WorldPacket const* WorldPackets::Ticket::GMTicketGetTicketResponse::Write()
return &_worldPacket;
}
+
+void WorldPackets::Ticket::GMTicketCreate::Read()
+{
+ _worldPacket >> Map;
+ _worldPacket >> Pos;
+ _worldPacket >> Flags;
+
+ uint16 descLength = _worldPacket.ReadBits(11);
+ Description = _worldPacket.ReadString(descLength);
+ _worldPacket.ResetBitPos();
+
+ NeedMoreHelp = _worldPacket.ReadBit();
+ NeedResponse = _worldPacket.ReadBit();
+ _worldPacket >> DataLength;
+
+ if (DataLength > 0)
+ {
+ _worldPacket >> ChatHistoryData.TextCount;
+ for (uint8 i = 0; i < ChatHistoryData.TextCount; ++i)
+ ChatHistoryData.Sent.push_back(_worldPacket.read<uint32>());
+
+ _worldPacket >> ChatHistoryData.DecompressedSize;
+
+ //Note: don't ask why, but it works...
+ uint32 realLength = DataLength - ((ChatHistoryData.TextCount * 4) + 5);
+ ChatHistoryData.Data.resize(realLength);
+ _worldPacket.read(ChatHistoryData.Data.contents(), realLength);
+ }
+}
+
+void WorldPackets::Ticket::GMTicketUpdateText::Read()
+{
+ uint16 descLength = _worldPacket.ReadBits(11);
+ Description = _worldPacket.ReadString(descLength);
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketUpdate::Write()
+{
+ _worldPacket << uint8(Result);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketStatusUpdate::Write()
+{
+ _worldPacket << int32(StatusInt);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketResponse::Write()
+{
+ _worldPacket << uint32(TicketID);
+ _worldPacket << uint32(ResponseID);
+
+ _worldPacket.WriteBits(Description.size(), 11);
+ _worldPacket.WriteBits(ResponseText.size(), 14);
+ _worldPacket.FlushBits();
+
+ _worldPacket.WriteString(Description);
+ _worldPacket.WriteString(ResponseText);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketResolveResponse::Write()
+{
+ _worldPacket.WriteBit(ShowSurvey);
+
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
+
+void WorldPackets::Ticket::GMSurveySubmit::Read()
+{
+ _worldPacket >> SurveyID;
+
+ SurveyQuestion.resize(_worldPacket.ReadBits(4));
+ uint16 commentLength = _worldPacket.ReadBits(11);
+
+ for (auto& q : SurveyQuestion)
+ {
+ _worldPacket >> q.QuestionID;
+ _worldPacket >> q.Answer;
+ q.AnswerComment = _worldPacket.ReadString(_worldPacket.ReadBits(11));
+ }
+
+ Comment = _worldPacket.ReadString(commentLength);
+}
+
+void WorldPackets::Ticket::SupportTicketSubmitBug::Read()
+{
+ _worldPacket >> Header;
+ Note = _worldPacket.ReadString(_worldPacket.ReadBits(10));
+}
+
+void WorldPackets::Ticket::SupportTicketSubmitSuggestion::Read()
+{
+ _worldPacket >> Header;
+ Note = _worldPacket.ReadString(_worldPacket.ReadBits(10));
+}
+
+WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine::SupportTicketChatLine(ByteBuffer& data)
+{
+ data >> Timestamp;
+ uint16 textLength = data.ReadBits(12);
+ data.ResetBitPos();
+ Text = data.ReadString(textLength);
+}
+
+WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine::SupportTicketChatLine(uint32 timestamp, std::string const& text)
+{
+ Timestamp = timestamp;
+ Text = text;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLine& line)
+{
+ data >> line.Timestamp;
+ uint16 textLength = data.ReadBits(12);
+ data.ResetBitPos();
+ line.Text = data.ReadString(textLength);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLog& chatlog)
+{
+ uint32 linesCount = data.read<uint32>();
+
+ for (uint32 i = 0; i < linesCount; i++)
+ chatlog.Lines.emplace_back(data);
+
+ bool hasReportLineIndex = data.ReadBit();
+ if (hasReportLineIndex)
+ chatlog.ReportLineIndex.Set(data.read<uint32>());
+
+ data.ResetBitPos();
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketMailInfo& mail)
+{
+ data >> mail.MailID;
+ uint16 bodyLength = data.ReadBits(13);
+ uint16 subjectLength = data.ReadBits(9);
+
+ mail.MailBody = data.ReadString(bodyLength);
+ mail.MailSubject = data.ReadString(subjectLength);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketCalendarEventInfo& event)
+{
+ data >> event.EventID;
+ data >> event.InviteID;
+ uint8 titleLength = data.ReadBits(8);
+
+ event.EventTitle = data.ReadString(titleLength);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketPetInfo& pet)
+{
+ data >> pet.PetID;
+ uint8 nameLength = data.ReadBits(8);
+
+ pet.PetName = data.ReadString(nameLength);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketGuildInfo& guild)
+{
+ data >> guild.GuildID;
+ uint8 nameLength = data.ReadBits(8);
+
+ guild.GuildName = data.ReadString(nameLength);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::Struct5E4383& str)
+{
+ data >> str.RideTicket;
+ data >> str._40;
+ data >> str._56;
+ data >> str._72;
+
+ uint8 _88Length = data.ReadBits(8);
+ uint8 _217Length = data.ReadBits(8);
+ uint8 _1242Length = data.ReadBits(8);
+
+ str._88 = data.ReadString(_88Length);
+ str._217 = data.ReadString(_217Length);
+ str._1242 = data.ReadString(_1242Length);
+
+ return data;
+}
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Ticket::SupportTicketSubmitComplaint::Struct5E3DFB& str)
+{
+ data >> str.RideTicket;
+
+ uint16 _32Length = data.ReadBits(9);
+ data.ResetBitPos();
+
+ str._32 = data.ReadString(_32Length);
+
+ return data;
+}
+
+void WorldPackets::Ticket::SupportTicketSubmitComplaint::Read()
+{
+ _worldPacket >> Header;
+ _worldPacket >> ChatLog;
+ _worldPacket >> TargetCharacterGUID;
+ ComplaintType = _worldPacket.ReadBits(5);
+
+ uint16 noteLength = _worldPacket.ReadBits(10);
+ bool hasMailInfo = _worldPacket.ReadBit();
+ bool hasCalendarInfo = _worldPacket.ReadBit();
+ bool hasPetInfo = _worldPacket.ReadBit();
+ bool hasGuildInfo = _worldPacket.ReadBit();
+ bool has5E4383 = _worldPacket.ReadBit();
+ bool has5E3DFB = _worldPacket.ReadBit();
+
+ _worldPacket.ResetBitPos();
+
+ Note = _worldPacket.ReadString(noteLength);
+
+ if (hasMailInfo)
+ {
+ _worldPacket >> MailInfo.Value;
+ MailInfo.HasValue = true;
+ }
+
+ if (hasCalendarInfo)
+ {
+ _worldPacket >> CalenderInfo.Value;
+ CalenderInfo.HasValue = true;
+ }
+
+ if (hasPetInfo)
+ {
+ _worldPacket >> PetInfo.Value;
+ PetInfo.HasValue = true;
+ }
+
+ if (hasGuildInfo)
+ {
+ _worldPacket >> GuildInfo.Value;
+ GuildInfo.HasValue = true;
+ }
+
+ if (has5E4383)
+ {
+ _worldPacket >> _5E4383.Value;
+ _5E4383.HasValue = true;
+ }
+
+ if (has5E3DFB)
+ {
+ _worldPacket >> _5E3DFB.Value;
+ _5E3DFB.HasValue = true;
+ }
+}
+
+WorldPacket const* WorldPackets::Ticket::ComplaintResult::Write()
+{
+ _worldPacket << uint32(ComplaintType);
+ _worldPacket << uint8(Result);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/TicketPackets.h b/src/server/game/Server/Packets/TicketPackets.h
index 8a5ae862f84..e11adf912ed 100644
--- a/src/server/game/Server/Packets/TicketPackets.h
+++ b/src/server/game/Server/Packets/TicketPackets.h
@@ -19,11 +19,20 @@
#define TicketPackets_h__
#include "Packet.h"
+#include "LFGPackets.h"
+#include <G3D/Vector3.h>
namespace WorldPackets
{
namespace Ticket
{
+ struct SupportTicketHeader
+ {
+ int32 MapID = 0;
+ G3D::Vector3 Position;
+ float Facing = 0.0f;
+ };
+
class GMTicketGetSystemStatus final : public ClientPacket
{
public:
@@ -107,6 +116,120 @@ namespace WorldPackets
Optional<GMTicketInfo> Info;
};
+ class GMTicketCreate final : public ClientPacket
+ {
+ public:
+ struct ChatHistoryData
+ {
+ uint8 TextCount = 0;
+ std::vector<uint32> Sent;
+ uint32 DecompressedSize = 0;
+ ByteBuffer Data;
+ };
+
+ GMTicketCreate(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_CREATE, std::move(packet)) { }
+
+ void Read() override;
+
+ int32 Map = 0;
+ G3D::Vector3 Pos;
+ uint8 Flags = 0;
+ std::string Description;
+ bool NeedMoreHelp = false;
+ bool NeedResponse = false;
+ uint32 DataLength = 0;
+ ChatHistoryData ChatHistoryData; ///< Compressed Data
+ };
+
+ class GMTicketUpdateText final : public ClientPacket
+ {
+ public:
+ GMTicketUpdateText(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_UPDATE_TEXT, std::move(packet)) { }
+
+ void Read() override;
+
+ std::string Description;
+ };
+
+ class GMTicketUpdate final : public ServerPacket
+ {
+ public:
+ GMTicketUpdate() : ServerPacket(SMSG_GM_TICKET_UPDATE, 1) { }
+
+ WorldPacket const* Write() override;
+
+ uint8 Result = 0;
+ };
+
+ class GMTicketStatusUpdate final : public ServerPacket
+ {
+ public:
+ GMTicketStatusUpdate() : ServerPacket(SMSG_GM_TICKET_STATUS_UPDATE, 4) { }
+
+ WorldPacket const* Write() override;
+
+ int32 StatusInt = 0;
+ };
+
+ class GMTicketDelete final : public ClientPacket
+ {
+ public:
+ GMTicketDelete(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_DELETE_TICKET, std::move(packet)) { }
+
+ void Read() override { }
+ };
+
+ class GMTicketResponse final : public ServerPacket
+ {
+ public:
+ GMTicketResponse() : ServerPacket(SMSG_GM_TICKET_RESPONSE, 12) { }
+
+ WorldPacket const* Write() override;
+
+ uint32 TicketID = 0;
+ uint32 ResponseID = 0;
+ std::string Description;
+ std::string ResponseText;
+ };
+
+ class GMTicketResponseResolve final : public ClientPacket
+ {
+ public:
+ GMTicketResponseResolve(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_RESPONSE_RESOLVE, std::move(packet)) { }
+
+ void Read() override { }
+ };
+
+ class GMTicketResolveResponse final : public ServerPacket
+ {
+ public:
+ GMTicketResolveResponse() : ServerPacket(SMSG_GM_TICKET_RESOLVE_RESPONSE, 1) { }
+
+ WorldPacket const* Write() override;
+
+ bool ShowSurvey = false;
+ };
+
+ class GMSurveySubmit final : public ClientPacket
+ {
+ public:
+ struct GMSurveyQuestion
+ {
+ int32 QuestionID = 0;
+ uint8 Answer = 0;
+ std::string AnswerComment;
+ };
+
+ GMSurveySubmit(WorldPacket&& packet) : ClientPacket(CMSG_GM_SURVEY_SUBMIT, std::move(packet)) { }
+
+ void Read() override;
+
+ int32 SurveyID = 0;
+ std::vector<GMSurveyQuestion> SurveyQuestion;
+ std::string Comment;
+
+ };
+
class GMTicketAcknowledgeSurvey final : public ClientPacket
{
public:
@@ -124,6 +247,118 @@ namespace WorldPackets
WorldPacket const* Write() { return &_worldPacket; }
};
+
+ class SupportTicketSubmitBug final : public ClientPacket
+ {
+ public:
+ SupportTicketSubmitBug(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_BUG, std::move(packet)) { }
+
+ void Read() override;
+
+ SupportTicketHeader Header;
+ std::string Note;
+ };
+
+ class SupportTicketSubmitSuggestion final : public ClientPacket
+ {
+ public:
+ SupportTicketSubmitSuggestion(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, std::move(packet)) { }
+
+ void Read() override;
+
+ SupportTicketHeader Header;
+ std::string Note;
+ };
+
+ class SupportTicketSubmitComplaint final : public ClientPacket
+ {
+ public:
+ struct SupportTicketChatLine
+ {
+ SupportTicketChatLine(ByteBuffer& data);
+ SupportTicketChatLine(uint32 timestamp, std::string const& text);
+
+ uint32 Timestamp = 0;
+ std::string Text;
+ };
+
+ struct SupportTicketChatLog
+ {
+ std::vector<SupportTicketChatLine> Lines;
+ Optional<uint32> ReportLineIndex;
+ };
+
+ struct SupportTicketMailInfo
+ {
+ int32 MailID = 0;
+ std::string MailSubject;
+ std::string MailBody;
+ };
+
+ struct SupportTicketCalendarEventInfo
+ {
+ ObjectGuid EventID;
+ ObjectGuid InviteID;
+ std::string EventTitle;
+ };
+
+ struct SupportTicketPetInfo
+ {
+ ObjectGuid PetID;
+ std::string PetName;
+ };
+
+ struct SupportTicketGuildInfo
+ {
+ ObjectGuid GuildID;
+ std::string GuildName;
+ };
+
+ struct Struct5E4383
+ {
+ WorldPackets::LFG::RideTicket RideTicket;
+ ObjectGuid _40;
+ ObjectGuid _56;
+ ObjectGuid _72;
+ std::string _88;
+ std::string _217;
+ std::string _1242;
+ };
+
+ struct Struct5E3DFB
+ {
+ WorldPackets::LFG::RideTicket RideTicket;
+ std::string _32;
+ };
+
+ SupportTicketSubmitComplaint(WorldPacket&& packet) : ClientPacket(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, std::move(packet)) { }
+
+ void Read() override;
+
+ SupportTicketHeader Header;
+ SupportTicketChatLog ChatLog;
+ ObjectGuid TargetCharacterGUID;
+ uint8 ComplaintType = 0;
+ std::string Note;
+ Optional<SupportTicketMailInfo> MailInfo;
+ Optional<SupportTicketCalendarEventInfo> CalenderInfo;
+ Optional<SupportTicketPetInfo> PetInfo;
+ Optional<SupportTicketGuildInfo> GuildInfo;
+ Optional<Struct5E4383> _5E4383;
+ Optional<Struct5E3DFB> _5E3DFB;
+
+ };
+
+ class ComplaintResult final : public ServerPacket
+ {
+ public:
+ ComplaintResult() : ServerPacket(SMSG_COMPLAINT_RESULT, 9) { }
+
+ WorldPacket const* Write() override;
+
+ uint32 ComplaintType = 0;
+ uint8 Result = 0;
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index de285fb1ed6..43ffe3e223e 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -379,20 +379,19 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_GET_UNDELETE_COOLDOWN_STATUS, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GetUndeleteCooldownStatus, &WorldSession::HandleGetUndeleteCooldownStatus);
DEFINE_OPCODE_HANDLER_OLD(CMSG_GHOST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_INVIS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_LAG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReportLag );
+ DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_LAG_REPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_NUKE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SET_SECURITY_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit );
+ DEFINE_HANDLER(CMSG_GM_SURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMSurveySubmit, &WorldSession::HandleGMSurveySubmit);
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
//DEFINE_HANDLER(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketAcknowledgeSurvey, &WorldSession::HandleGMTicketAcknowledgeSurveyOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_CREATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketCreateOpcode );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_DELETE_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketDeleteOpcode );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- //DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketGetCaseStatus, &WorldSession::HandleGMTicketGetCaseStatusOpcode);
- DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetSystemStatus, &WorldSession::HandleGMTicketSystemStatusOpcode);
- DEFINE_HANDLER(CMSG_GM_TICKET_GET_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetTicket, &WorldSession::HandleGMTicketGetTicketOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_RESPONSE_RESOLVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_UPDATE_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode );
+ DEFINE_HANDLER(CMSG_GM_TICKET_CREATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketCreate, &WorldSession::HandleGMTicketCreateOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_DELETE_TICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketDelete, &WorldSession::HandleGMTicketDeleteOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketGetCaseStatus, &WorldSession::HandleGMTicketGetCaseStatusOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetSystemStatus, &WorldSession::HandleGMTicketSystemStatusOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_GET_TICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetTicket, &WorldSession::HandleGMTicketGetTicketOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_RESPONSE_RESOLVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketResponseResolve, &WorldSession::HandleGMResponseResolve);
+ DEFINE_HANDLER(CMSG_GM_TICKET_UPDATE_TEXT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketUpdateText, &WorldSession::HandleGMTicketUpdateTextOpcode);
DEFINE_HANDLER(CMSG_GOSSIP_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode);
DEFINE_HANDLER(CMSG_GOSSIP_SELECT_OPTION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, WorldPackets::NPC::GossipSelectOption, &WorldSession::HandleGossipSelectOptionOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_GRANT_LEVEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel );
@@ -804,9 +803,9 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_STOP_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_STORE_LOOT_IN_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SUMMON_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_BUG, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
+ DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_BUG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitBug, &WorldSession::HandleSupportTicketSubmitBug);
+ DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitComplaint, &WorldSession::HandleSupportTicketSubmitComplaint);
+ DEFINE_HANDLER(CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::SupportTicketSubmitSuggestion, &WorldSession::HandleSupportTicketSubmitSuggestion);
DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_COMMS_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode);
@@ -1239,14 +1238,14 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_MESSAGECHAT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESOLVE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESOLVE_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 7bc9488dd26..f4bfac9225e 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -292,13 +292,13 @@ enum OpcodeClient : uint32
CMSG_GM_SET_SECURITY_GROUP = 0xBADD,
CMSG_GM_SURVEY_SUBMIT = 0xBADD,
CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY = 0xBADD,
- CMSG_GM_TICKET_CREATE = 0xBADD,
- CMSG_GM_TICKET_DELETE_TICKET = 0xBADD,
- CMSG_GM_TICKET_GET_CASE_STATUS = 0xBADD,
- CMSG_GM_TICKET_GET_SYSTEM_STATUS = 0xBADD,
- CMSG_GM_TICKET_GET_TICKET = 0xBADD,
- CMSG_GM_TICKET_RESPONSE_RESOLVE = 0xBADD,
- CMSG_GM_TICKET_UPDATE_TEXT = 0xBADD,
+ CMSG_GM_TICKET_CREATE = 0x19A4,
+ CMSG_GM_TICKET_DELETE_TICKET = 0x1B39,
+ CMSG_GM_TICKET_GET_CASE_STATUS = 0x17E1,
+ CMSG_GM_TICKET_GET_SYSTEM_STATUS = 0x1BB9,
+ CMSG_GM_TICKET_GET_TICKET = 0x1939,
+ CMSG_GM_TICKET_RESPONSE_RESOLVE = 0x19FB,
+ CMSG_GM_TICKET_UPDATE_TEXT = 0x19EB,
CMSG_GOSSIP_HELLO = 0x0483,
CMSG_GOSSIP_SELECT_OPTION = 0xBADD,
CMSG_GRANT_LEVEL = 0xBADD,
@@ -712,9 +712,9 @@ enum OpcodeClient : uint32
CMSG_STOP_DANCE = 0xBADD,
CMSG_STORE_LOOT_IN_SLOT = 0xBADD,
CMSG_SUMMON_RESPONSE = 0xBADD,
- CMSG_SUPPORT_TICKET_SUBMIT_BUG = 0xBADD,
- CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT = 0xBADD,
- CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION = 0xBADD,
+ CMSG_SUPPORT_TICKET_SUBMIT_BUG = 0x11BB,
+ CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT = 0x1BB1,
+ CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION = 0x1B63,
CMSG_SUSPEND_COMMS_ACK = 0x123C,
CMSG_SUSPEND_TOKEN_RESPONSE = 0x1273,
CMSG_SWAP_INV_ITEM = 0x00C5,
@@ -1171,14 +1171,14 @@ enum OpcodeServer : uint32
SMSG_GM_PLAYER_INFO = 0xBADD,
SMSG_GM_REQUEST_PLAYER_INFO = 0xBADD,
SMSG_GM_SUMMON = 0xBADD,
- SMSG_GM_TICKET_CASE_STATUS = 0xBADD,
- SMSG_GM_TICKET_GET_TICKET_RESPONSE = 0xBADD,
- SMSG_GM_TICKET_RESOLVE_RESPONSE = 0xBADD,
- SMSG_GM_TICKET_RESPONSE = 0xBADD,
- SMSG_GM_TICKET_RESPONSE_ERROR = 0xBADD,
- SMSG_GM_TICKET_STATUS_UPDATE = 0xBADD,
- SMSG_GM_TICKET_SYSTEM_STATUS = 0xBADD,
- SMSG_GM_TICKET_UPDATE = 0xBADD,
+ SMSG_GM_TICKET_CASE_STATUS = 0x086B,
+ SMSG_GM_TICKET_GET_TICKET_RESPONSE = 0x0183,
+ SMSG_GM_TICKET_RESOLVE_RESPONSE = 0x0869,
+ SMSG_GM_TICKET_RESPONSE = 0x1729,
+ SMSG_GM_TICKET_RESPONSE_ERROR = 0x0A33,
+ SMSG_GM_TICKET_STATUS_UPDATE = 0x0B74,
+ SMSG_GM_TICKET_SYSTEM_STATUS = 0x134C,
+ SMSG_GM_TICKET_UPDATE = 0x193A,
SMSG_GOD_MODE = 0xBADD,
SMSG_GOSSIP_COMPLETE = 0xBADD,
SMSG_GOSSIP_MESSAGE = 0x0117,
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 54c995589a4..c7ea26b7adf 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -358,10 +358,18 @@ namespace WorldPackets
namespace Ticket
{
+ class GMSurveySubmit;
+ class GMTicketAcknowledgeSurvey;
+ class GMTicketCreate;
+ class GMTicketDelete;
class GMTicketGetSystemStatus;
class GMTicketGetCaseStatus;
class GMTicketGetTicket;
- class GMTicketAcknowledgeSurvey;
+ class GMTicketResponseResolve;
+ class GMTicketUpdateText;
+ class SupportTicketSubmitBug;
+ class SupportTicketSubmitSuggestion;
+ class SupportTicketSubmitComplaint;
}
namespace Trade
@@ -840,15 +848,17 @@ class WorldSession
void HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCancel& logoutCancel);
// GM Ticket opcodes
- void HandleGMTicketCreateOpcode(WorldPacket& recvPacket);
- void HandleGMTicketUpdateOpcode(WorldPacket& recvPacket);
- void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket);
+ void HandleGMTicketCreateOpcode(WorldPackets::Ticket::GMTicketCreate& packet);
+ void HandleGMTicketUpdateTextOpcode(WorldPackets::Ticket::GMTicketUpdateText& packet);
+ void HandleGMTicketDeleteOpcode(WorldPackets::Ticket::GMTicketDelete& packet);
void HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& packet);
void HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& packet);
void HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& packet);
- void HandleGMSurveySubmit(WorldPacket& recvPacket);
- void HandleReportLag(WorldPacket& recvPacket);
- void HandleGMResponseResolve(WorldPacket& recvPacket);
+ void HandleGMSurveySubmit(WorldPackets::Ticket::GMSurveySubmit& packet);
+ void HandleGMResponseResolve(WorldPackets::Ticket::GMTicketResponseResolve& packet);
+ void HandleSupportTicketSubmitBug(WorldPackets::Ticket::SupportTicketSubmitBug& packet);
+ void HandleSupportTicketSubmitSuggestion(WorldPackets::Ticket::SupportTicketSubmitSuggestion& packet);
+ void HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet);
void HandleTogglePvP(WorldPacket& recvPacket);
diff --git a/src/server/game/Support/SupportMgr.cpp b/src/server/game/Support/SupportMgr.cpp
new file mode 100644
index 00000000000..9183c2f7fde
--- /dev/null
+++ b/src/server/game/Support/SupportMgr.cpp
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 "Chat.h"
+#include "Language.h"
+#include "SupportMgr.h"
+
+inline time_t GetAge(uint64 t) { return (time(nullptr) - t) / DAY; }
+
+Ticket::Ticket() : _id(0), _mapId(0), _createTime(0) { }
+
+Ticket::Ticket(Player* player) : _id(0), _mapId(0), _createTime(time(nullptr))
+{
+ _playerGuid = player->GetGUID();
+}
+
+Ticket::~Ticket() { }
+
+void Ticket::TeleportTo(Player* player) const
+{
+ player->TeleportTo(_mapId, _pos.x, _pos.y, _pos.z, 0.0f, 0);
+}
+
+std::string Ticket::FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const
+{
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ if (szClosedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName);
+ if (szAssignedToName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName);
+ if (szUnassignedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName);
+ if (szDeletedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName);
+ return ss.str();
+}
+
+GmTicket::GmTicket() : _lastModifiedTime(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), _needResponse(false), _needMoreHelp(false) { }
+
+GmTicket::GmTicket(Player* player) : Ticket(player), _lastModifiedTime(time(nullptr)), _completed(false), _escalatedStatus(TICKET_UNASSIGNED),
+_viewed(false), _needResponse(false), _needMoreHelp(false)
+{
+ _id = sSupportMgr->GenerateGmTicketId();
+}
+
+GmTicket::~GmTicket() { }
+
+void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp)
+{
+ _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default)
+ _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket"
+}
+
+void GmTicket::SetUnassigned()
+{
+ _assignedTo.Clear();
+ switch (_escalatedStatus)
+ {
+ case TICKET_ASSIGNED: _escalatedStatus = TICKET_UNASSIGNED;
+ break;
+ case TICKET_ESCALATED_ASSIGNED: _escalatedStatus = TICKET_IN_ESCALATION_QUEUE;
+ break;
+ case TICKET_UNASSIGNED:
+ case TICKET_IN_ESCALATION_QUEUE:
+ default:
+ break;
+ }
+}
+
+void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log)
+{
+ std::stringstream ss(log);
+ std::stringstream newss;
+ std::string line;
+ while (std::getline(ss, line) && !time.empty())
+ {
+ newss << secsToTimeString(time.front()) << ": " << line << "\n";
+ time.pop_front();
+ }
+
+ _chatLog = newss.str();
+}
+
+void GmTicket::SendResponse(WorldSession* session) const
+{
+ WorldPackets::Ticket::GMTicketResponse resp;
+ resp.TicketID = GetId();
+ resp.ResponseID = 2; //TODO : research
+ resp.Description = GetDescription();
+ resp.ResponseText = GetResponse();
+
+ session->SendPacket(resp.Write());
+}
+
+void GmTicket::LoadFromDB(Field* fields)
+{
+ uint8 idx = 0;
+ _id = fields[ idx].GetUInt32();
+ _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64());
+ _description = fields[++idx].GetString();
+ _createTime = fields[++idx].GetUInt32();
+ _mapId = fields[++idx].GetUInt16();
+ _pos.x = fields[++idx].GetFloat();
+ _pos.y = fields[++idx].GetFloat();
+ _pos.z = fields[++idx].GetFloat();
+ _lastModifiedTime = fields[++idx].GetUInt32();
+
+ int64 closedBy = fields[++idx].GetInt64();
+ if (closedBy == 0)
+ _closedBy = ObjectGuid::Empty;
+ else if (closedBy < 0)
+ _closedBy.SetRawValue(0, uint64(closedBy));
+ else
+ _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy));
+
+ uint64 assignedTo = fields[++idx].GetUInt64();
+ if (assignedTo == 0)
+ _assignedTo = ObjectGuid::Empty;
+ else
+ _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo);
+
+ _comment = fields[++idx].GetString();
+ _response = fields[++idx].GetString();
+ _completed = fields[++idx].GetBool();
+ _escalatedStatus = GMTicketEscalationStatus(fields[++idx].GetUInt8());
+ _viewed = fields[++idx].GetBool();
+ _needMoreHelp = fields[++idx].GetBool();
+}
+
+void GmTicket::SaveToDB(SQLTransaction& trans) const
+{
+ uint8 idx = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET);
+ stmt->setUInt32(idx, _id);
+ stmt->setUInt64(++idx, _playerGuid.GetCounter());
+ stmt->setString(++idx, _description);
+ stmt->setUInt32(++idx, _createTime);
+ stmt->setUInt16(++idx, _mapId);
+ stmt->setFloat(++idx, _pos.x);
+ stmt->setFloat(++idx, _pos.y);
+ stmt->setFloat(++idx, _pos.z);
+ stmt->setUInt32(++idx, uint32(_lastModifiedTime));
+ stmt->setInt64(++idx, int64(_closedBy.GetCounter()));
+ stmt->setUInt64(++idx, _assignedTo.GetCounter());
+ stmt->setString(++idx, _comment);
+ stmt->setString(++idx, _response);
+ stmt->setBool(++idx, _completed);
+ stmt->setUInt8(++idx, uint8(_escalatedStatus));
+ stmt->setBool(++idx, _viewed);
+ stmt->setBool(++idx, _needMoreHelp);
+
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
+}
+
+void GmTicket::DeleteFromDB()
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_TICKET);
+ stmt->setUInt32(0, _id);
+ CharacterDatabase.Execute(stmt);
+}
+
+std::string GmTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const
+{
+ time_t curTime = time(nullptr);
+
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str());
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(curTime - _lastModifiedTime, true, false)).c_str());
+
+ std::string name;
+ if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name))
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
+
+ if (detailed)
+ {
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _description.c_str());
+ if (!_comment.empty())
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str());
+ if (!_response.empty())
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, _response.c_str());
+ }
+ return ss.str();
+}
+
+std::string GmTicket::FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const
+{
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ if (szClosedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName);
+ if (szAssignedToName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName);
+ if (szUnassignedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName);
+ if (szDeletedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName);
+ if (szCompletedName)
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName);
+ return ss.str();
+}
+
+BugTicket::BugTicket() : _facing(0.0f) { }
+
+BugTicket::BugTicket(Player* player) : Ticket(player)
+{
+ _id = sSupportMgr->GenerateBugId();
+}
+
+BugTicket::~BugTicket() { }
+
+void BugTicket::LoadFromDB(Field* fields)
+{
+ uint8 idx = 0;
+ _id = fields[ idx].GetUInt32();
+ _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64());
+ _note = fields[++idx].GetString();
+ _createTime = fields[++idx].GetUInt32();
+ _mapId = fields[++idx].GetUInt32();
+ _pos.x = fields[++idx].GetFloat();
+ _pos.y = fields[++idx].GetFloat();
+ _pos.z = fields[++idx].GetFloat();
+ _facing = fields[++idx].GetFloat();
+
+ int64 closedBy = fields[++idx].GetInt64();
+ if (closedBy == 0)
+ _closedBy = ObjectGuid::Empty;
+ else if (closedBy < 0)
+ _closedBy.SetRawValue(0, uint64(closedBy));
+ else
+ _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy));
+
+ uint64 assignedTo = fields[++idx].GetUInt64();
+ if (assignedTo == 0)
+ _assignedTo = ObjectGuid::Empty;
+ else
+ _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo);
+
+ _comment = fields[++idx].GetString();
+}
+
+void BugTicket::SaveToDB(SQLTransaction& trans) const
+{
+ uint8 idx = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_BUG);
+ stmt->setUInt32(idx, _id);
+ stmt->setUInt64(++idx, _playerGuid.GetCounter());
+ stmt->setString(++idx, _note);
+ stmt->setUInt32(++idx, _mapId);
+ stmt->setFloat(++idx, _pos.x);
+ stmt->setFloat(++idx, _pos.y);
+ stmt->setFloat(++idx, _pos.z);
+ stmt->setFloat(++idx, _facing);
+ stmt->setInt64(++idx, _closedBy.GetCounter());
+ stmt->setUInt64(++idx, _assignedTo.GetCounter());
+ stmt->setString(++idx, _comment);
+
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
+}
+
+void BugTicket::DeleteFromDB()
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_BUG);
+ stmt->setUInt32(0, _id);
+ CharacterDatabase.Execute(stmt);
+}
+
+std::string BugTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const
+{
+ time_t curTime = time(nullptr);
+
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str());
+
+ std::string name;
+ if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name))
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
+
+ if (detailed)
+ {
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str());
+ if (!_comment.empty())
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str());
+ }
+ return ss.str();
+}
+
+ComplaintTicket::ComplaintTicket() : _facing(0.0f), _complaintType(GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE) { }
+
+ComplaintTicket::ComplaintTicket(Player* player) : Ticket(player), _facing(0.0f), _complaintType(GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE)
+{
+ _id = sSupportMgr->GenerateComplaintId();
+}
+
+ComplaintTicket::~ComplaintTicket() { }
+
+void ComplaintTicket::LoadFromDB(Field* fields)
+{
+ uint8 idx = 0;
+ _id = fields[ idx].GetUInt32();
+ _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64());
+ _note = fields[++idx].GetString();
+ _createTime = fields[++idx].GetUInt32();
+ _mapId = fields[++idx].GetUInt32();
+ _pos.x = fields[++idx].GetFloat();
+ _pos.y = fields[++idx].GetFloat();
+ _pos.z = fields[++idx].GetFloat();
+ _facing = fields[++idx].GetFloat();
+ _targetCharacterGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64());
+ _complaintType = GMSupportComplaintType(fields[++idx].GetUInt8());
+ int32 reportLineIndex = fields[++idx].GetInt32();
+ if (reportLineIndex != -1)
+ _chatLog.ReportLineIndex.Set(reportLineIndex);
+
+ int64 closedBy = fields[++idx].GetInt64();
+ if (closedBy == 0)
+ _closedBy = ObjectGuid::Empty;
+ else if (closedBy < 0)
+ _closedBy.SetRawValue(0, uint64(closedBy));
+ else
+ _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy));
+
+ uint64 assignedTo = fields[++idx].GetUInt64();
+ if (assignedTo == 0)
+ _assignedTo = ObjectGuid::Empty;
+ else
+ _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo);
+
+ _comment = fields[++idx].GetString();
+}
+
+void ComplaintTicket::LoadChatLineFromDB(Field* fields)
+{
+ _chatLog.Lines.emplace_back(fields[0].GetUInt32(), fields[1].GetString());
+}
+
+void ComplaintTicket::SaveToDB(SQLTransaction& trans) const
+{
+ bool isInTransaction = bool(trans);
+ if (!isInTransaction)
+ trans = CharacterDatabase.BeginTransaction();
+
+ uint8 idx = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_COMPLAINT);
+ stmt->setUInt32(idx, _id);
+ stmt->setUInt64(++idx, _playerGuid.GetCounter());
+ stmt->setString(++idx, _note);
+ stmt->setUInt32(++idx, _mapId);
+ stmt->setFloat(++idx, _pos.x);
+ stmt->setFloat(++idx, _pos.y);
+ stmt->setFloat(++idx, _pos.z);
+ stmt->setFloat(++idx, _facing);
+ stmt->setUInt64(++idx, _targetCharacterGuid.GetCounter());
+ stmt->setUInt8(++idx, _complaintType);
+ if (_chatLog.ReportLineIndex.HasValue)
+ stmt->setInt32(++idx, _chatLog.ReportLineIndex.Value);
+ else
+ stmt->setInt32(++idx, -1); // empty ReportLineIndex
+ stmt->setInt64(++idx, _closedBy.GetCounter());
+ stmt->setUInt64(++idx, _assignedTo.GetCounter());
+ stmt->setString(++idx, _comment);
+ trans->Append(stmt);
+
+ uint32 lineIndex = 0;
+ for (auto const& c : _chatLog.Lines)
+ {
+ idx = 0;
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_COMPLAINT_CHATLINE);
+ stmt->setUInt32(idx, _id);
+ stmt->setUInt32(++idx, lineIndex);
+ stmt->setUInt32(++idx, c.Timestamp);
+ stmt->setString(++idx, c.Text);
+
+ trans->Append(stmt);
+ ++lineIndex;
+ }
+
+ if (!isInTransaction)
+ CharacterDatabase.CommitTransaction(trans);
+}
+
+void ComplaintTicket::DeleteFromDB()
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT);
+ stmt->setUInt32(0, _id);
+ CharacterDatabase.Execute(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_COMPLAINT_CHATLOG);
+ stmt->setUInt32(0, _id);
+}
+
+std::string ComplaintTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const
+{
+ time_t curTime = time(nullptr);
+
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str());
+
+ std::string name;
+ if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name))
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
+
+ if (detailed)
+ {
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str());
+ if (!_comment.empty())
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str());
+ }
+ return ss.str();
+}
+
+SuggestionTicket::SuggestionTicket() : _facing(0.0f) { }
+
+SuggestionTicket::SuggestionTicket(Player* player) : Ticket(player)
+{
+ _id = sSupportMgr->GenerateSuggestionId();
+}
+
+SuggestionTicket::~SuggestionTicket() { }
+
+void SuggestionTicket::LoadFromDB(Field* fields)
+{
+ uint8 idx = 0;
+ _id = fields[ idx].GetUInt32();
+ _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++idx].GetUInt64());
+ _note = fields[++idx].GetString();
+ _createTime = fields[++idx].GetUInt32();
+ _mapId = fields[++idx].GetUInt32();
+ _pos.x = fields[++idx].GetFloat();
+ _pos.y = fields[++idx].GetFloat();
+ _pos.z = fields[++idx].GetFloat();
+ _facing = fields[++idx].GetFloat();
+
+ int64 closedBy = fields[++idx].GetInt64();
+ if (closedBy == 0)
+ _closedBy = ObjectGuid::Empty;
+ else if (closedBy < 0)
+ _closedBy.SetRawValue(0, uint64(closedBy));
+ else
+ _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy));
+
+ uint64 assignedTo = fields[++idx].GetUInt64();
+ if (assignedTo == 0)
+ _assignedTo = ObjectGuid::Empty;
+ else
+ _assignedTo = ObjectGuid::Create<HighGuid::Player>(assignedTo);
+
+ _comment = fields[++idx].GetString();
+}
+
+void SuggestionTicket::SaveToDB(SQLTransaction& trans) const
+{
+ uint8 idx = 0;
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_SUGGESTION);
+ stmt->setUInt32(idx, _id);
+ stmt->setUInt64(++idx, _playerGuid.GetCounter());
+ stmt->setString(++idx, _note);
+ stmt->setUInt32(++idx, _mapId);
+ stmt->setFloat(++idx, _pos.x);
+ stmt->setFloat(++idx, _pos.y);
+ stmt->setFloat(++idx, _pos.z);
+ stmt->setFloat(++idx, _facing);
+ stmt->setInt64(++idx, _closedBy.GetCounter());
+ stmt->setUInt64(++idx, _assignedTo.GetCounter());
+ stmt->setString(++idx, _comment);
+
+ CharacterDatabase.ExecuteOrAppend(trans, stmt);
+}
+
+void SuggestionTicket::DeleteFromDB()
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_SUGGESTION);
+ stmt->setUInt32(0, _id);
+ CharacterDatabase.Execute(stmt);
+}
+
+std::string SuggestionTicket::FormatViewMessageString(ChatHandler& handler, bool detailed) const
+{
+ time_t curTime = time(nullptr);
+
+ std::stringstream ss;
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str());
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str());
+
+ std::string name;
+ if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name))
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
+
+ if (detailed)
+ {
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _note.c_str());
+ if (!_comment.empty())
+ ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str());
+ }
+ return ss.str();
+}
+
+SupportMgr::SupportMgr() : _lastGmTicketId(0), _lastBugId(0), _lastComplaintId(0), _lastSuggestionId(0), _openGmTicketCount(0),
+_openBugTicketCount(0), _openComplaintTicketCount(0), _openSuggestionTicketCount(0) { }
+
+SupportMgr::~SupportMgr()
+{
+ for (auto const& t : _gmTicketList)
+ delete t.second;
+
+ for (auto const& b : _bugTicketList)
+ delete b.second;
+
+ for (auto const& c : _complaintTicketList)
+ delete c.second;
+
+ for (auto const& s : _suggestionTicketList)
+ delete s.second;
+}
+
+void SupportMgr::Initialize()
+{
+ SetSupportSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_ENABLED));
+ SetTicketSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED));
+ SetBugSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED));
+ SetComplaintSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED));
+ SetSuggestionSystemStatus(sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED));
+}
+
+template<>
+GmTicket* SupportMgr::GetTicket<GmTicket>(uint32 ticketId)
+{
+ GmTicketList::const_iterator itr = _gmTicketList.find(ticketId);
+ if (itr != _gmTicketList.end())
+ return itr->second;
+
+ return nullptr;
+
+}
+
+template<>
+BugTicket* SupportMgr::GetTicket<BugTicket>(uint32 bugId)
+{
+ BugTicketList::const_iterator itr = _bugTicketList.find(bugId);
+ if (itr != _bugTicketList.end())
+ return itr->second;
+
+ return nullptr;
+
+}
+
+template<>
+ComplaintTicket* SupportMgr::GetTicket<ComplaintTicket>(uint32 complaintId)
+{
+ ComplaintTicketList::const_iterator itr = _complaintTicketList.find(complaintId);
+ if (itr != _complaintTicketList.end())
+ return itr->second;
+
+ return nullptr;
+}
+
+template<>
+SuggestionTicket* SupportMgr::GetTicket<SuggestionTicket>(uint32 suggestionId)
+{
+ SuggestionTicketList::const_iterator itr = _suggestionTicketList.find(suggestionId);
+ if (itr != _suggestionTicketList.end())
+ return itr->second;
+
+ return nullptr;
+
+}
+
+template<>
+uint32 SupportMgr::GetOpenTicketCount<GmTicket>() const { return _openGmTicketCount; }
+
+template<>
+uint32 SupportMgr::GetOpenTicketCount<BugTicket>() const { return _openBugTicketCount; }
+
+template<>
+uint32 SupportMgr::GetOpenTicketCount<ComplaintTicket>() const { return _openComplaintTicketCount; }
+
+template<>
+uint32 SupportMgr::GetOpenTicketCount<SuggestionTicket>() const { return _openSuggestionTicketCount; }
+
+void SupportMgr::LoadGmTickets()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (auto const& c : _gmTicketList)
+ delete c.second;
+ _gmTicketList.clear();
+
+ _lastGmTicketId = 0;
+ _openGmTicketCount = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_TICKETS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_ticket` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ GmTicket* ticket = new GmTicket();
+ ticket->LoadFromDB(fields);
+
+ if (!ticket->IsClosed())
+ ++_openGmTicketCount;
+
+ uint32 id = ticket->GetId();
+ if (_lastGmTicketId < id)
+ _lastGmTicketId = id;
+
+ _gmTicketList[id] = ticket;
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u GM tickets in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SupportMgr::LoadBugTickets()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (auto const& c : _bugTicketList)
+ delete c.second;
+ _bugTicketList.clear();
+
+ _lastBugId = 0;
+ _openBugTicketCount = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_BUGS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 GM bugs. DB table `gm_bug` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ BugTicket* bug = new BugTicket();
+ bug->LoadFromDB(fields);
+
+ if (!bug->IsClosed())
+ ++_openBugTicketCount;
+
+ uint32 id = bug->GetId();
+ if (_lastBugId < id)
+ _lastBugId = id;
+
+ _bugTicketList[id] = bug;
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u GM bugs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SupportMgr::LoadComplaintTickets()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (auto const& c : _complaintTicketList)
+ delete c.second;
+ _complaintTicketList.clear();
+
+ _lastComplaintId = 0;
+ _openComplaintTicketCount = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINTS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 GM complaints. DB table `gm_complaint` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+ PreparedStatement* chatLogStmt;
+ PreparedQueryResult chatLogResult;
+ do
+ {
+ Field* fields = result->Fetch();
+ ComplaintTicket* complaint = new ComplaintTicket();
+ complaint->LoadFromDB(fields);
+
+ if (!complaint->IsClosed())
+ ++_openComplaintTicketCount;
+
+ uint32 id = complaint->GetId();
+ if (_lastComplaintId < id)
+ _lastComplaintId = id;
+
+ chatLogStmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_COMPLAINT_CHATLINES);
+ chatLogResult = CharacterDatabase.Query(stmt);
+
+ if (chatLogResult)
+ {
+ do
+ {
+ Field* chatLineFields = chatLogResult->Fetch();
+ complaint->LoadChatLineFromDB(chatLineFields);
+ } while (chatLogResult->NextRow());
+ }
+
+ _complaintTicketList[id] = complaint;
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u GM complaints in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SupportMgr::LoadSuggestionTickets()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (auto const& c : _suggestionTicketList)
+ delete c.second;
+ _suggestionTicketList.clear();
+
+ _lastSuggestionId = 0;
+ _openSuggestionTicketCount = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_SUGGESTIONS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (!result)
+ {
+ TC_LOG_INFO("server.loading", ">> Loaded 0 GM suggestions. DB table `gm_suggestion` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ SuggestionTicket* suggestion = new SuggestionTicket();
+ suggestion->LoadFromDB(fields);
+
+ if (!suggestion->IsClosed())
+ ++_openSuggestionTicketCount;
+
+ uint32 id = suggestion->GetId();
+ if (_lastSuggestionId < id)
+ _lastSuggestionId = id;
+
+ _suggestionTicketList[id] = suggestion;
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u GM suggestions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void SupportMgr::AddTicket(GmTicket* ticket)
+{
+ _gmTicketList[ticket->GetId()] = ticket;
+ if (!ticket->IsClosed())
+ ++_openGmTicketCount;
+
+ SQLTransaction trans = SQLTransaction(nullptr);
+ ticket->SaveToDB(trans);
+}
+
+void SupportMgr::AddTicket(BugTicket* ticket)
+{
+ _bugTicketList[ticket->GetId()] = ticket;
+ if (!ticket->IsClosed())
+ ++_openBugTicketCount;
+
+ SQLTransaction trans = SQLTransaction(nullptr);
+ ticket->SaveToDB(trans);
+}
+
+void SupportMgr::AddTicket(ComplaintTicket* ticket)
+{
+ _complaintTicketList[ticket->GetId()] = ticket;
+ if (!ticket->IsClosed())
+ ++_openComplaintTicketCount;
+
+ SQLTransaction trans = SQLTransaction(nullptr);
+ ticket->SaveToDB(trans);
+}
+
+void SupportMgr::AddTicket(SuggestionTicket* ticket)
+{
+ _suggestionTicketList[ticket->GetId()] = ticket;
+ if (!ticket->IsClosed())
+ ++_openSuggestionTicketCount;
+
+ SQLTransaction trans = SQLTransaction(nullptr);
+ ticket->SaveToDB(trans);
+}
+
+template<>
+void SupportMgr::RemoveTicket<GmTicket>(uint32 ticketId)
+{
+ if (GmTicket* ticket = GetTicket<GmTicket>(ticketId))
+ {
+ ticket->DeleteFromDB();
+ _gmTicketList.erase(ticketId);
+ delete ticket;
+ }
+}
+
+template<>
+void SupportMgr::RemoveTicket<BugTicket>(uint32 ticketId)
+{
+ if (BugTicket* ticket = GetTicket<BugTicket>(ticketId))
+ {
+ ticket->DeleteFromDB();
+ _bugTicketList.erase(ticketId);
+ delete ticket;
+ }
+}
+
+template<>
+void SupportMgr::RemoveTicket<ComplaintTicket>(uint32 ticketId)
+{
+ if (ComplaintTicket* ticket = GetTicket<ComplaintTicket>(ticketId))
+ {
+ ticket->DeleteFromDB();
+ _complaintTicketList.erase(ticketId);
+ delete ticket;
+ }
+}
+
+template<>
+void SupportMgr::RemoveTicket<SuggestionTicket>(uint32 ticketId)
+{
+ if (SuggestionTicket* ticket = GetTicket<SuggestionTicket>(ticketId))
+ {
+ ticket->DeleteFromDB();
+ _suggestionTicketList.erase(ticketId);
+ delete ticket;
+ }
+}
+
+template<>
+void SupportMgr::CloseTicket<GmTicket>(uint32 ticketId, ObjectGuid closedBy)
+{
+ if (GmTicket* ticket = GetTicket<GmTicket>(ticketId))
+ {
+ SQLTransaction trans = SQLTransaction(NULL);
+ ticket->SetClosedBy(closedBy);
+ if (!closedBy.IsEmpty())
+ --_openGmTicketCount;
+ ticket->SaveToDB(trans);
+ }
+}
+
+template<>
+void SupportMgr::CloseTicket<BugTicket>(uint32 ticketId, ObjectGuid closedBy)
+{
+ if (BugTicket* ticket = GetTicket<BugTicket>(ticketId))
+ {
+ SQLTransaction trans = SQLTransaction(NULL);
+ ticket->SetClosedBy(closedBy);
+ if (!closedBy.IsEmpty())
+ --_openBugTicketCount;
+ ticket->SaveToDB(trans);
+ }
+}
+
+template<>
+void SupportMgr::CloseTicket<ComplaintTicket>(uint32 ticketId, ObjectGuid closedBy)
+{
+ if (ComplaintTicket* ticket = GetTicket<ComplaintTicket>(ticketId))
+ {
+ SQLTransaction trans = SQLTransaction(NULL);
+ ticket->SetClosedBy(closedBy);
+ if (!closedBy.IsEmpty())
+ --_openComplaintTicketCount;
+ ticket->SaveToDB(trans);
+ }
+}
+
+template<>
+void SupportMgr::CloseTicket<SuggestionTicket>(uint32 ticketId, ObjectGuid closedBy)
+{
+ if (SuggestionTicket* ticket = GetTicket<SuggestionTicket>(ticketId))
+ {
+ SQLTransaction trans = SQLTransaction(NULL);
+ ticket->SetClosedBy(closedBy);
+ if (!closedBy.IsEmpty())
+ --_openSuggestionTicketCount;
+ ticket->SaveToDB(trans);
+ }
+}
+
+template<>
+void SupportMgr::ResetTickets<GmTicket>()
+{
+ for (auto const& c : _gmTicketList)
+ delete c.second;
+ _gmTicketList.clear();
+
+ _lastGmTicketId = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_TICKETS);
+ CharacterDatabase.Execute(stmt);
+}
+
+template<>
+void SupportMgr::ResetTickets<BugTicket>()
+{
+ for (auto const& c : _bugTicketList)
+ delete c.second;
+ _bugTicketList.clear();
+
+ _lastBugId = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_BUGS);
+ CharacterDatabase.Execute(stmt);
+}
+
+template<>
+void SupportMgr::ResetTickets<ComplaintTicket>()
+{
+ for (auto const& c : _complaintTicketList)
+ delete c.second;
+ _complaintTicketList.clear();
+
+ _lastComplaintId = 0;
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINTS));
+ trans->Append(CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_COMPLAINT_CHATLOGS));
+ CharacterDatabase.CommitTransaction(trans);
+}
+
+template<>
+void SupportMgr::ResetTickets<SuggestionTicket>()
+{
+ for (auto const& c : _suggestionTicketList)
+ delete c.second;
+ _suggestionTicketList.clear();
+
+ _lastSuggestionId = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_SUGGESTIONS);
+ CharacterDatabase.Execute(stmt);
+}
+
+template<>
+void SupportMgr::ShowList<GmTicket>(ChatHandler& handler, bool onlineOnly) const
+{
+ handler.SendSysMessage(onlineOnly ? LANG_COMMAND_TICKETSHOWONLINELIST : LANG_COMMAND_TICKETSHOWLIST);
+ for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr)
+ if (!itr->second->IsClosed() && !itr->second->IsCompleted())
+ if (!onlineOnly || itr->second->GetPlayer())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowList<GmTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST);
+ for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr)
+ if (!itr->second->IsClosed() && !itr->second->IsCompleted())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowList<BugTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST);
+ for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr)
+ if (!itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowList<ComplaintTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST);
+ for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr)
+ if (!itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowList<SuggestionTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWLIST);
+ for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr)
+ if (!itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowClosedList<GmTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST);
+ for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr)
+ if (itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowClosedList<BugTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST);
+ for (BugTicketList::const_iterator itr = _bugTicketList.begin(); itr != _bugTicketList.end(); ++itr)
+ if (itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowClosedList<ComplaintTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST);
+ for (ComplaintTicketList::const_iterator itr = _complaintTicketList.begin(); itr != _complaintTicketList.end(); ++itr)
+ if (itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+template<>
+void SupportMgr::ShowClosedList<SuggestionTicket>(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST);
+ for (SuggestionTicketList::const_iterator itr = _suggestionTicketList.begin(); itr != _suggestionTicketList.end(); ++itr)
+ if (itr->second->IsClosed())
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+void SupportMgr::ShowGmEscalatedList(ChatHandler& handler) const
+{
+ handler.SendSysMessage(LANG_COMMAND_TICKETSHOWESCALATEDLIST);
+ for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr)
+ if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE)
+ handler.SendSysMessage(itr->second->FormatViewMessageString(handler).c_str());
+}
+
+void SupportMgr::SendGmTicket(WorldSession* session, GmTicket* ticket) const
+{
+ WorldPackets::Ticket::GMTicketGetTicketResponse response;
+
+ if (ticket)
+ {
+ response.Result = GMTICKET_STATUS_HASTEXT;
+ response.Info.HasValue = true;
+
+ response.Info.Value.TicketID = ticket->GetId();
+ response.Info.Value.TicketDescription = ticket->GetDescription();
+ response.Info.Value.Category = ticket->GetEscalatedStatus();
+ response.Info.Value.TicketOpenTime = GetAge(ticket->GetLastModifiedTime());
+ response.Info.Value.OldestTicketTime = sSupportMgr->GetOldestOpenTicket() ? GetAge(sSupportMgr->GetOldestOpenTicket()->GetLastModifiedTime()) : float(0);
+ response.Info.Value.UpdateTime = GetAge(sSupportMgr->GetLastChange());
+ response.Info.Value.AssignedToGM = ticket->IsAssigned();
+ response.Info.Value.OpenedByGM = ticket->IsViewed();
+ response.Info.Value.WaitTimeOverrideMessage = "";
+ response.Info.Value.WaitTimeOverrideMinutes = 0;
+ }
+ else
+ response.Result = GMTICKET_STATUS_DEFAULT;
+
+ session->SendPacket(response.Write());
+}
+
+void SupportMgr::SendGmTicketUpdate(WorldSession* session, GMTicketResponse response) const
+{
+ WorldPackets::Ticket::GMTicketUpdate update;
+ update.Result = response;
+
+ session->SendPacket(update.Write());
+}
diff --git a/src/server/game/Support/SupportMgr.h b/src/server/game/Support/SupportMgr.h
new file mode 100644
index 00000000000..eddb3cebf75
--- /dev/null
+++ b/src/server/game/Support/SupportMgr.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 SupportMgr_h__
+#define SupportMgr_h__
+
+#include "ObjectMgr.h"
+#include "Player.h"
+#include "TicketPackets.h"
+
+class ChatHandler;
+
+// from blizzard lua
+enum GMTicketSystemStatus
+{
+ GMTICKET_QUEUE_STATUS_DISABLED = 0,
+ GMTICKET_QUEUE_STATUS_ENABLED = 1
+};
+
+enum GMTicketStatus
+{
+ GMTICKET_STATUS_HASTEXT = 0x06,
+ GMTICKET_STATUS_DEFAULT = 0x0A
+};
+
+enum GMTicketResponse
+{
+ GMTICKET_RESPONSE_ALREADY_EXIST = 1,
+ GMTICKET_RESPONSE_CREATE_SUCCESS = 2,
+ GMTICKET_RESPONSE_CREATE_ERROR = 3,
+ GMTICKET_RESPONSE_UPDATE_SUCCESS = 4,
+ GMTICKET_RESPONSE_UPDATE_ERROR = 5,
+ GMTICKET_RESPONSE_TICKET_DELETED = 9
+};
+
+// from blizzard lua
+enum GMTicketOpenedByGMStatus
+{
+ GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED = 0, // ticket has never been opened by a gm
+ GMTICKET_OPENEDBYGM_STATUS_OPENED = 1 // ticket has been opened by a gm
+};
+
+// from Blizzard LUA:
+// GMTICKET_ASSIGNEDTOGM_STATUS_NOT_ASSIGNED = 0; -- ticket is not currently assigned to a gm
+// GMTICKET_ASSIGNEDTOGM_STATUS_ASSIGNED = 1; -- ticket is assigned to a normal gm
+// GMTICKET_ASSIGNEDTOGM_STATUS_ESCALATED = 2; -- ticket is in the escalation queue
+// 3 is a custom value and should never actually be sent
+enum GMTicketEscalationStatus
+{
+ TICKET_UNASSIGNED = 0,
+ TICKET_ASSIGNED = 1,
+ TICKET_IN_ESCALATION_QUEUE = 2,
+ TICKET_ESCALATED_ASSIGNED = 3
+};
+
+enum GMSupportComplaintType
+{
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_NONE = 0,
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_LANGUAGE = 2,
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_PLAYERNAME = 4,
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_CHEAT = 15,
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_GUILDNAME = 23,
+ GMTICKET_SUPPORT_COMPLAINT_TYPE_SPAMMING = 24
+};
+
+using ChatLog = WorldPackets::Ticket::SupportTicketSubmitComplaint::SupportTicketChatLog;
+
+class Ticket
+{
+public:
+ Ticket();
+ Ticket(Player* player);
+ virtual ~Ticket();
+
+ bool IsClosed() const { return !_closedBy.IsEmpty(); }
+ bool IsFromPlayer(ObjectGuid guid) const { return guid == _playerGuid; }
+ bool IsAssigned() const { return !_assignedTo.IsEmpty(); }
+ bool IsAssignedTo(ObjectGuid guid) const { return guid == _assignedTo; }
+ bool IsAssignedNotTo(ObjectGuid guid) const { return IsAssigned() && !IsAssignedTo(guid); }
+
+ uint32 GetId() const { return _id; }
+ ObjectGuid GetPlayerGuid() const { return _playerGuid; }
+ Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); }
+ Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); }
+ ObjectGuid GetAssignedToGUID() const { return _assignedTo; }
+ std::string GetAssignedToName() const
+ {
+ std::string name;
+ if (!_assignedTo.IsEmpty())
+ ObjectMgr::GetPlayerNameByGUID(_assignedTo, name);
+
+ return name;
+ }
+ std::string const& GetComment() { return _comment; }
+
+ virtual void SetAssignedTo(ObjectGuid guid) { _assignedTo = guid; }
+ virtual void SetAssignedTo(ObjectGuid /*guid*/, bool /*isAdmin*/) { }
+ virtual void SetUnassigned() { _assignedTo.Clear(); }
+ void SetClosedBy(ObjectGuid value) { _closedBy = value; }
+ void SetComment(std::string const& comment) { _comment = comment; }
+ void SetPosition(uint32 mapId, G3D::Vector3& pos)
+ {
+ _mapId = mapId;
+ _pos = pos;
+ }
+
+ virtual void LoadFromDB(Field* fields) = 0;
+ virtual void SaveToDB(SQLTransaction& trans) const = 0;
+ virtual void DeleteFromDB() = 0;
+
+ void TeleportTo(Player* player) const;
+
+ virtual std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const = 0;
+ virtual std::string FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const;
+
+protected:
+ uint32 _id;
+ ObjectGuid _playerGuid;
+ uint16 _mapId;
+ G3D::Vector3 _pos;
+ uint64 _createTime;
+ ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it.
+ ObjectGuid _assignedTo;
+ std::string _comment;
+};
+
+
+class GmTicket : public Ticket
+{
+public:
+ GmTicket();
+ GmTicket(Player* player);
+ ~GmTicket();
+
+ bool IsCompleted() const { return _completed; }
+ bool IsViewed() const { return _viewed; }
+
+ bool GetNeedMoreHelp() const { return _needMoreHelp; }
+ std::string const& GetDescription() const { return _description; }
+ uint64 GetLastModifiedTime() const { return _lastModifiedTime; }
+ GMTicketEscalationStatus GetEscalatedStatus() const { return _escalatedStatus; }
+ std::string const& GetResponse() const { return _response; }
+
+ void SetAssignedTo(ObjectGuid guid, bool isAdmin) override
+ {
+ _assignedTo = guid;
+ if (isAdmin && _escalatedStatus == TICKET_IN_ESCALATION_QUEUE)
+ _escalatedStatus = TICKET_ESCALATED_ASSIGNED;
+ else if (_escalatedStatus == TICKET_UNASSIGNED)
+ _escalatedStatus = TICKET_ASSIGNED;
+ }
+ void SetEscalatedStatus(GMTicketEscalationStatus escalatedStatus) { _escalatedStatus = escalatedStatus; }
+ void SetCompleted() { _completed = true; }
+ void SetDescription(std::string const& description)
+ {
+ _description = description;
+ _lastModifiedTime = uint64(time(NULL));
+ }
+ void SetViewed() { _viewed = true; }
+ void SetGmAction(uint32 needResponse, bool needMoreHelp);
+ void SetUnassigned() override;
+
+ void AppendResponse(std::string const& response) { _response += response; }
+
+ void SetChatLog(std::list<uint32> time, std::string const& log);
+ std::string const& GetChatLog() const { return _chatLog; }
+
+ void SendResponse(WorldSession* session) const;
+
+ void LoadFromDB(Field* fields) override;
+ void SaveToDB(SQLTransaction& trans) const override;
+ void DeleteFromDB() override;
+
+ std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override;
+ std::string FormatViewMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const override;
+
+private:
+ std::string _description;
+ uint64 _lastModifiedTime;
+ bool _completed;
+ GMTicketEscalationStatus _escalatedStatus;
+ bool _viewed;
+ bool _needResponse; /// @todo find out the use of this, and then store it in DB
+ bool _needMoreHelp;
+ std::string _response;
+ std::string _chatLog; // No need to store in db, will be refreshed every session client side
+};
+
+class BugTicket : public Ticket
+{
+public:
+ BugTicket();
+ BugTicket(Player* player);
+ ~BugTicket();
+
+ std::string const& GetNote() const { return _note; }
+
+ void SetFacing(float facing) { _facing = facing; }
+ void SetNote(std::string const& note) { _note = note; }
+
+ void LoadFromDB(Field* fields) override;
+ void SaveToDB(SQLTransaction& trans) const override;
+ void DeleteFromDB() override;
+
+ using Ticket::FormatViewMessageString;
+ std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override;
+
+private:
+ float _facing;
+ std::string _note;
+};
+
+class ComplaintTicket : public Ticket
+{
+public:
+ ComplaintTicket();
+ ComplaintTicket(Player* player);
+ ~ComplaintTicket();
+
+ ObjectGuid GetTargetCharacterGuid() const { return _targetCharacterGuid; }
+ GMSupportComplaintType GetComplaintType() const { return _complaintType; }
+ std::string const& GetNote() const { return _note; }
+
+ void SetFacing(float facing) { _facing = facing; }
+ void SetTargetCharacterGuid(ObjectGuid targetCharacterGuid)
+ {
+ _targetCharacterGuid = targetCharacterGuid;
+ }
+ void SetComplaintType(GMSupportComplaintType type) { _complaintType = type; }
+ void SetChatLog(ChatLog const& log) { _chatLog = log; }
+ void SetNote(std::string const& note) { _note = note; }
+
+ void LoadFromDB(Field* fields) override;
+ void LoadChatLineFromDB(Field* fields);
+ void SaveToDB(SQLTransaction& trans) const override;
+ void DeleteFromDB() override;
+
+ using Ticket::FormatViewMessageString;
+ std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override;
+
+private:
+ float _facing;
+ ObjectGuid _targetCharacterGuid;
+ GMSupportComplaintType _complaintType;
+ ChatLog _chatLog;
+ std::string _note;
+};
+
+class SuggestionTicket : public Ticket
+{
+public:
+ SuggestionTicket();
+ SuggestionTicket(Player* player);
+ ~SuggestionTicket();
+
+ std::string const& GetNote() const { return _note; }
+ void SetNote(std::string const& note) { _note = note; }
+
+ void SetFacing(float facing) { _facing = facing; }
+
+ void LoadFromDB(Field* fields) override;
+ void SaveToDB(SQLTransaction& trans) const override;
+ void DeleteFromDB() override;
+
+ using Ticket::FormatViewMessageString;
+ std::string FormatViewMessageString(ChatHandler& handler, bool detailed = false) const override;
+
+private:
+ float _facing;
+ std::string _note;
+};
+
+typedef std::map<uint32, BugTicket*> BugTicketList;
+typedef std::map<uint32, ComplaintTicket*> ComplaintTicketList;
+typedef std::map<uint32, SuggestionTicket*> SuggestionTicketList;
+typedef std::map<uint32, GmTicket*> GmTicketList;
+
+class SupportMgr
+{
+private:
+ SupportMgr();
+ ~SupportMgr();
+
+public:
+ static SupportMgr* instance()
+ {
+ static SupportMgr instance;
+ return &instance;
+ }
+
+ template<typename T>
+ T* GetTicket(uint32 ticketId);
+
+ GmTicket* GetGmTicketByPlayerGuid(ObjectGuid playerGuid) const
+ {
+ for (auto const& c : _gmTicketList)
+ if (c.second->GetPlayerGuid() == playerGuid && !c.second->IsClosed())
+ return c.second;
+
+ return nullptr;
+ }
+
+ ComplaintTicketList GetComplaintsByPlayerGuid(ObjectGuid playerGuid) const
+ {
+ ComplaintTicketList ret;
+ for (auto const& c : _complaintTicketList)
+ if (c.second->GetPlayerGuid() == playerGuid)
+ ret.insert(c);
+
+ return ret;
+ }
+
+ GmTicket* GetOldestOpenTicket()
+ {
+ for (GmTicketList::const_iterator itr = _gmTicketList.begin(); itr != _gmTicketList.end(); ++itr)
+ if (itr->second && !itr->second->IsClosed() && !itr->second->IsCompleted())
+ return itr->second;
+
+ return nullptr;
+ }
+
+ void Initialize();
+
+ bool GetSupportSystemStatus() { return _supportSystemStatus; }
+ bool GetTicketSystemStatus() { return _supportSystemStatus && _ticketSystemStatus; }
+ bool GetBugSystemStatus() { return _supportSystemStatus && _bugSystemStatus; }
+ bool GetComplaintSystemStatus() { return _supportSystemStatus && _complaintSystemStatus; }
+ bool GetSuggestionSystemStatus() { return _supportSystemStatus && _suggestionSystemStatus; }
+ uint64 GetLastChange() const { return _lastChange; }
+ template<typename T>
+ uint32 GetOpenTicketCount() const;
+
+ void SetSupportSystemStatus(bool status) { _supportSystemStatus = status; }
+ void SetTicketSystemStatus(bool status) { _ticketSystemStatus = status; }
+ void SetBugSystemStatus(bool status) { _bugSystemStatus = status; }
+ void SetComplaintSystemStatus(bool status) { _complaintSystemStatus = status; }
+ void SetSuggestionSystemStatus(bool status) { _suggestionSystemStatus = status; }
+
+ void LoadGmTickets();
+ void LoadBugTickets();
+ void LoadComplaintTickets();
+ void LoadSuggestionTickets();
+
+ void AddTicket(GmTicket* ticket);
+ void AddTicket(BugTicket* ticket);
+ void AddTicket(ComplaintTicket* ticket);
+ void AddTicket(SuggestionTicket* ticket);
+
+ template<typename T>
+ void RemoveTicket(uint32 ticketId);
+
+ template<typename T>
+ void CloseTicket(uint32 ticketId, ObjectGuid closedBy);
+
+ template<typename T>
+ void ResetTickets();
+
+ template<typename T>
+ void ShowList(ChatHandler& handler) const;
+
+ template<typename T>
+ void ShowList(ChatHandler& handler, bool onlineOnly) const;
+
+ template<typename T>
+ void ShowClosedList(ChatHandler& handler) const;
+
+ void ShowGmEscalatedList(ChatHandler& handler) const;
+
+ void UpdateLastChange() { _lastChange = uint64(time(nullptr)); }
+
+ void SendGmTicket(WorldSession* session, GmTicket* ticket) const;
+ void SendGmTicketUpdate(WorldSession* session, GMTicketResponse response) const;
+
+ uint32 GenerateGmTicketId() { return ++_lastGmTicketId; }
+ uint32 GenerateBugId() { return ++_lastBugId; }
+ uint32 GenerateComplaintId() { return ++_lastComplaintId; }
+ uint32 GenerateSuggestionId() { return ++_lastSuggestionId; }
+
+private:
+ bool _supportSystemStatus;
+ bool _ticketSystemStatus;
+ bool _bugSystemStatus;
+ bool _complaintSystemStatus;
+ bool _suggestionSystemStatus;
+ GmTicketList _gmTicketList;
+ BugTicketList _bugTicketList;
+ ComplaintTicketList _complaintTicketList;
+ SuggestionTicketList _suggestionTicketList;
+ uint32 _lastGmTicketId;
+ uint32 _lastBugId;
+ uint32 _lastComplaintId;
+ uint32 _lastSuggestionId;
+ uint32 _openGmTicketCount;
+ uint32 _openBugTicketCount;
+ uint32 _openComplaintTicketCount;
+ uint32 _openSuggestionTicketCount;
+ uint64 _lastChange;
+};
+
+#define sSupportMgr SupportMgr::instance()
+
+#endif // SupportMgr_h__
diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp
deleted file mode 100644
index 84dac6cc175..00000000000
--- a/src/server/game/Tickets/TicketMgr.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * 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 "Common.h"
-#include "TicketMgr.h"
-#include "TicketPackets.h"
-#include "DatabaseEnv.h"
-#include "Log.h"
-#include "Language.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "Chat.h"
-#include "World.h"
-#include "Player.h"
-#include "Opcodes.h"
-
-inline time_t GetAge(uint64 t) { return (time(NULL) - t) / DAY; }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// GM ticket
-GmTicket::GmTicket() : _id(0), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
- _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
- _needResponse(false), _needMoreHelp(false) { }
-
-GmTicket::GmTicket(Player* player) : _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(time(NULL)), _lastModifiedTime(time(NULL)),
- _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
- _needResponse(false), _needMoreHelp(false)
-{
- _id = sTicketMgr->GenerateTicketId();
- _playerName = player->GetName();
- _playerGuid = player->GetGUID();
-}
-
-GmTicket::~GmTicket() { }
-
-bool GmTicket::LoadFromDB(Field* fields)
-{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
- // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket
- uint8 index = 0;
- _id = fields[ index].GetUInt32();
- _playerGuid = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt64());
- _playerName = fields[++index].GetString();
- _message = fields[++index].GetString();
- _createTime = fields[++index].GetUInt32();
- _mapId = fields[++index].GetUInt16();
- _posX = fields[++index].GetFloat();
- _posY = fields[++index].GetFloat();
- _posZ = fields[++index].GetFloat();
- _lastModifiedTime = fields[++index].GetUInt32();
- int64 closedBy = fields[++index].GetInt64();
- if (closedBy < 0)
- _closedBy.SetRawValue(0, uint64(closedBy));
- else
- _closedBy = ObjectGuid::Create<HighGuid::Player>(uint64(closedBy));
-
- _assignedTo = ObjectGuid::Create<HighGuid::Player>(fields[++index].GetUInt64());
- _comment = fields[++index].GetString();
- _response = fields[++index].GetString();
- _completed = fields[++index].GetBool();
- _escalatedStatus = GMTicketEscalationStatus(fields[++index].GetUInt8());
- _viewed = fields[++index].GetBool();
- _needMoreHelp = fields[++index].GetBool();
- return true;
-}
-
-void GmTicket::SaveToDB(SQLTransaction& trans) const
-{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- // ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, completed, escalated, viewed
- uint8 index = 0;
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET);
- stmt->setUInt32( index, _id);
- stmt->setUInt64(++index, _playerGuid.GetCounter());
- stmt->setString(++index, _playerName);
- stmt->setString(++index, _message);
- stmt->setUInt32(++index, uint32(_createTime));
- stmt->setUInt16(++index, _mapId);
- stmt->setFloat (++index, _posX);
- stmt->setFloat (++index, _posY);
- stmt->setFloat (++index, _posZ);
- stmt->setUInt32(++index, uint32(_lastModifiedTime));
- stmt->setInt64 (++index, int64(_closedBy.GetCounter()));
- stmt->setUInt64(++index, _assignedTo.GetCounter());
- stmt->setString(++index, _comment);
- stmt->setString(++index, _response);
- stmt->setBool (++index, _completed);
- stmt->setUInt8 (++index, uint8(_escalatedStatus));
- stmt->setBool (++index, _viewed);
- stmt->setBool (++index, _needMoreHelp);
-
- CharacterDatabase.ExecuteOrAppend(trans, stmt);
-}
-
-void GmTicket::DeleteFromDB()
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GM_TICKET);
- stmt->setUInt32(0, _id);
- CharacterDatabase.Execute(stmt);
-}
-
-void GmTicket::SendResponse(WorldSession* session) const
-{
- WorldPacket data(SMSG_GM_TICKET_RESPONSE);
- data << uint32(1); // responseID
- data << uint32(_id); // ticketID
- data << _message.c_str();
-
- size_t len = _response.size();
- char const* s = _response.c_str();
-
- for (int i = 0; i < 4; i++)
- {
- if (len)
- {
- size_t writeLen = std::min<size_t>(len, 3999);
- data.append(s, writeLen);
-
- len -= writeLen;
- s += writeLen;
- }
-
- data << uint8(0);
- }
-
- session->SendPacket(&data);
-}
-
-std::string GmTicket::FormatMessageString(ChatHandler& handler, bool detailed) const
-{
- time_t curTime = time(NULL);
-
- std::stringstream ss;
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, _playerName.c_str());
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str());
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(curTime - _lastModifiedTime, true, false)).c_str());
-
- std::string name;
- if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name))
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str());
-
- if (detailed)
- {
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _message.c_str());
- if (!_comment.empty())
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str());
- if (!_response.empty())
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, _response.c_str());
- }
- return ss.str();
-}
-
-std::string GmTicket::FormatMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const
-{
- std::stringstream ss;
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id);
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, _playerName.c_str());
- if (szClosedName)
- ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName);
- if (szAssignedToName)
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, szAssignedToName);
- if (szUnassignedName)
- ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTUNASSIGNED, szUnassignedName);
- if (szDeletedName)
- ss << handler.PGetParseString(LANG_COMMAND_TICKETDELETED, szDeletedName);
- if (szCompletedName)
- ss << handler.PGetParseString(LANG_COMMAND_TICKETCOMPLETED, szCompletedName);
- return ss.str();
-}
-
-void GmTicket::SetUnassigned()
-{
- _assignedTo.Clear();
- switch (_escalatedStatus)
- {
- case TICKET_ASSIGNED: _escalatedStatus = TICKET_UNASSIGNED; break;
- case TICKET_ESCALATED_ASSIGNED: _escalatedStatus = TICKET_IN_ESCALATION_QUEUE; break;
- case TICKET_UNASSIGNED:
- case TICKET_IN_ESCALATION_QUEUE:
- default:
- break;
- }
-}
-
-void GmTicket::SetPosition(uint32 mapId, float x, float y, float z)
-{
- _mapId = mapId;
- _posX = x;
- _posY = y;
- _posZ = z;
-}
-
-void GmTicket::SetGmAction(uint32 needResponse, bool needMoreHelp)
-{
- _needResponse = (needResponse == 17); // Requires GM response. 17 = true, 1 = false (17 is default)
- _needMoreHelp = needMoreHelp; // Requests further GM interaction on a ticket to which a GM has already responded. Basically means "has a new ticket"
-}
-
-void GmTicket::TeleportTo(Player* player) const
-{
- player->TeleportTo(_mapId, _posX, _posY, _posZ, 0.0f, 0);
-}
-
-void GmTicket::SetChatLog(std::list<uint32> time, std::string const& log)
-{
- std::stringstream ss(log);
- std::stringstream newss;
- std::string line;
- while (std::getline(ss, line) && !time.empty())
- {
- newss << secsToTimeString(time.front()) << ": " << line << "\n";
- time.pop_front();
- }
-
- _chatLog = newss.str();
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Ticket manager
-TicketMgr::TicketMgr() : _status(true), _lastTicketId(0), _lastSurveyId(0), _openTicketCount(0),
- _lastChange(time(NULL)) { }
-
-TicketMgr::~TicketMgr()
-{
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- delete itr->second;
-}
-
-void TicketMgr::Initialize()
-{
- SetStatus(sWorld->getBoolConfig(CONFIG_TICKET_SYSTEM_STATUS));
-}
-
-void TicketMgr::ResetTickets()
-{
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end();)
- {
- if (itr->second->IsClosed())
- {
- uint32 ticketId = itr->second->GetId();
- ++itr;
- sTicketMgr->RemoveTicket(ticketId);
- }
- else
- ++itr;
- }
-
- _lastTicketId = 0;
-
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_TICKETS);
-
- CharacterDatabase.Execute(stmt);
-}
-
-void TicketMgr::LoadTickets()
-{
- uint32 oldMSTime = getMSTime();
-
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- delete itr->second;
- _ticketList.clear();
-
- _lastTicketId = 0;
- _openTicketCount = 0;
-
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GM_TICKETS);
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
- if (!result)
- {
- TC_LOG_INFO("server.loading", ">> Loaded 0 GM tickets. DB table `gm_tickets` is empty!");
-
- return;
- }
-
- uint32 count = 0;
- do
- {
- Field* fields = result->Fetch();
- GmTicket* ticket = new GmTicket();
- if (!ticket->LoadFromDB(fields))
- {
- delete ticket;
- continue;
- }
- if (!ticket->IsClosed())
- ++_openTicketCount;
-
- // Update max ticket id if necessary
- uint32 id = ticket->GetId();
- if (_lastTicketId < id)
- _lastTicketId = id;
-
- _ticketList[id] = ticket;
- ++count;
- } while (result->NextRow());
-
- TC_LOG_INFO("server.loading", ">> Loaded %u GM tickets in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
-}
-
-void TicketMgr::LoadSurveys()
-{
- // we don't actually load anything into memory here as there's no reason to
- _lastSurveyId = 0;
-
- uint32 oldMSTime = getMSTime();
- if (QueryResult result = CharacterDatabase.Query("SELECT MAX(surveyId) FROM gm_surveys"))
- _lastSurveyId = (*result)[0].GetUInt32();
-
- TC_LOG_INFO("server.loading", ">> Loaded GM Survey count from database in %u ms", GetMSTimeDiffToNow(oldMSTime));
-
-}
-
-void TicketMgr::AddTicket(GmTicket* ticket)
-{
- _ticketList[ticket->GetId()] = ticket;
- if (!ticket->IsClosed())
- ++_openTicketCount;
- SQLTransaction trans = SQLTransaction(NULL);
- ticket->SaveToDB(trans);
-}
-
-void TicketMgr::CloseTicket(uint32 ticketId, ObjectGuid source)
-{
- if (GmTicket* ticket = GetTicket(ticketId))
- {
- SQLTransaction trans = SQLTransaction(NULL);
- ticket->SetClosedBy(source);
- if (!source.IsEmpty())
- --_openTicketCount;
- ticket->SaveToDB(trans);
- }
-}
-
-void TicketMgr::RemoveTicket(uint32 ticketId)
-{
- if (GmTicket* ticket = GetTicket(ticketId))
- {
- ticket->DeleteFromDB();
- _ticketList.erase(ticketId);
- delete ticket;
- }
-}
-
-void TicketMgr::ShowList(ChatHandler& handler, bool onlineOnly) const
-{
- handler.SendSysMessage(onlineOnly ? LANG_COMMAND_TICKETSHOWONLINELIST : LANG_COMMAND_TICKETSHOWLIST);
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- if (!itr->second->IsClosed() && !itr->second->IsCompleted())
- if (!onlineOnly || itr->second->GetPlayer())
- handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
-}
-
-void TicketMgr::ShowClosedList(ChatHandler& handler) const
-{
- handler.SendSysMessage(LANG_COMMAND_TICKETSHOWCLOSEDLIST);
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- if (itr->second->IsClosed())
- handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
-}
-
-void TicketMgr::ShowEscalatedList(ChatHandler& handler) const
-{
- handler.SendSysMessage(LANG_COMMAND_TICKETSHOWESCALATEDLIST);
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- if (!itr->second->IsClosed() && itr->second->GetEscalatedStatus() == TICKET_IN_ESCALATION_QUEUE)
- handler.SendSysMessage(itr->second->FormatMessageString(handler).c_str());
-}
-
-void TicketMgr::SendTicket(WorldSession* session, GmTicket* ticket) const
-{
- WorldPackets::Ticket::GMTicketGetTicketResponse response;
-
- if (ticket)
- {
- response.Result = GMTICKET_STATUS_HASTEXT;
- response.Info.HasValue = true;
-
- response.Info.Value.TicketID = ticket->GetId();
- response.Info.Value.TicketDescription = ticket->GetMessage();
- response.Info.Value.Category = ticket->GetNeedMoreHelp();
- response.Info.Value.TicketOpenTime = GetAge(ticket->GetLastModifiedTime());
- response.Info.Value.OldestTicketTime = sTicketMgr->GetOldestOpenTicket() ? GetAge(sTicketMgr->GetOldestOpenTicket()->GetLastModifiedTime()) : float(0);
- response.Info.Value.UpdateTime = GetAge(sTicketMgr->GetLastChange());
- response.Info.Value.AssignedToGM = ticket->IsAssigned();
- response.Info.Value.OpenedByGM = ticket->IsViewed();
- response.Info.Value.WaitTimeOverrideMessage = "";
- response.Info.Value.WaitTimeOverrideMinutes = 0;
- }
- else
- response.Result = GMTICKET_STATUS_DEFAULT;
-
- session->SendPacket(response.Write());
-}
diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h
deleted file mode 100644
index 577f29062b8..00000000000
--- a/src/server/game/Tickets/TicketMgr.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
- *
- * 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 _TICKETMGR_H
-#define _TICKETMGR_H
-
-#include <string>
-
-#include "ObjectMgr.h"
-
-class ChatHandler;
-
-// from blizzard lua
-enum GMTicketSystemStatus
-{
- GMTICKET_QUEUE_STATUS_DISABLED = 0,
- GMTICKET_QUEUE_STATUS_ENABLED = 1
-};
-
-enum GMTicketStatus
-{
- GMTICKET_STATUS_HASTEXT = 0x06,
- GMTICKET_STATUS_DEFAULT = 0x0A
-};
-
-enum GMTicketResponse
-{
- GMTICKET_RESPONSE_ALREADY_EXIST = 1,
- GMTICKET_RESPONSE_CREATE_SUCCESS = 2,
- GMTICKET_RESPONSE_CREATE_ERROR = 3,
- GMTICKET_RESPONSE_UPDATE_SUCCESS = 4,
- GMTICKET_RESPONSE_UPDATE_ERROR = 5,
- GMTICKET_RESPONSE_TICKET_DELETED = 9
-};
-
-// from Blizzard LUA:
-// GMTICKET_ASSIGNEDTOGM_STATUS_NOT_ASSIGNED = 0; -- ticket is not currently assigned to a gm
-// GMTICKET_ASSIGNEDTOGM_STATUS_ASSIGNED = 1; -- ticket is assigned to a normal gm
-// GMTICKET_ASSIGNEDTOGM_STATUS_ESCALATED = 2; -- ticket is in the escalation queue
-// 3 is a custom value and should never actually be sent
-enum GMTicketEscalationStatus
-{
- TICKET_UNASSIGNED = 0,
- TICKET_ASSIGNED = 1,
- TICKET_IN_ESCALATION_QUEUE = 2,
- TICKET_ESCALATED_ASSIGNED = 3
-};
-
-// from blizzard lua
-enum GMTicketOpenedByGMStatus
-{
- GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED = 0, // ticket has never been opened by a gm
- GMTICKET_OPENEDBYGM_STATUS_OPENED = 1 // ticket has been opened by a gm
-};
-
-enum LagReportType
-{
- LAG_REPORT_TYPE_LOOT = 1,
- LAG_REPORT_TYPE_AUCTION_HOUSE = 2,
- LAG_REPORT_TYPE_MAIL = 3,
- LAG_REPORT_TYPE_CHAT = 4,
- LAG_REPORT_TYPE_MOVEMENT = 5,
- LAG_REPORT_TYPE_SPELL = 6
-};
-
-class GmTicket
-{
-public:
- GmTicket();
- GmTicket(Player* player);
- ~GmTicket();
-
- bool IsClosed() const { return !_closedBy.IsEmpty(); }
- bool IsCompleted() const { return _completed; }
- bool IsFromPlayer(ObjectGuid guid) const { return guid == _playerGuid; }
- bool IsAssigned() const { return !_assignedTo.IsEmpty(); }
- bool IsAssignedTo(ObjectGuid guid) const { return guid == _assignedTo; }
- bool IsAssignedNotTo(ObjectGuid guid) const { return IsAssigned() && !IsAssignedTo(guid); }
- bool IsViewed() const { return _viewed; }
-
- uint32 GetId() const { return _id; }
- Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); }
- std::string const& GetPlayerName() const { return _playerName; }
- std::string const& GetMessage() const { return _message; }
- bool GetNeedMoreHelp() const { return _needMoreHelp; }
- Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); }
- ObjectGuid GetAssignedToGUID() const { return _assignedTo; }
- std::string GetAssignedToName() const
- {
- std::string name;
- // save queries if ticket is not assigned
- if (!_assignedTo.IsEmpty())
- ObjectMgr::GetPlayerNameByGUID(_assignedTo, name);
-
- return name;
- }
- uint64 GetLastModifiedTime() const { return _lastModifiedTime; }
- GMTicketEscalationStatus GetEscalatedStatus() const { return _escalatedStatus; }
-
- void SetEscalatedStatus(GMTicketEscalationStatus escalatedStatus) { _escalatedStatus = escalatedStatus; }
- void SetAssignedTo(ObjectGuid guid, bool isAdmin)
- {
- _assignedTo = guid;
- if (isAdmin && _escalatedStatus == TICKET_IN_ESCALATION_QUEUE)
- _escalatedStatus = TICKET_ESCALATED_ASSIGNED;
- else if (_escalatedStatus == TICKET_UNASSIGNED)
- _escalatedStatus = TICKET_ASSIGNED;
- }
- void SetClosedBy(ObjectGuid value) { _closedBy = value; }
- void SetCompleted() { _completed = true; }
- void SetMessage(std::string const& message)
- {
- _message = message;
- _lastModifiedTime = uint64(time(NULL));
- }
- void SetComment(std::string const& comment) { _comment = comment; }
- void SetViewed() { _viewed = true; }
- void SetUnassigned();
- void SetPosition(uint32 mapId, float x, float y, float z);
- void SetGmAction(uint32 needResponse, bool needMoreHelp);
-
- void AppendResponse(std::string const& response) { _response += response; }
-
- bool LoadFromDB(Field* fields);
- void SaveToDB(SQLTransaction& trans) const;
- void DeleteFromDB();
-
- void WritePacket(WorldPacket& data) const;
- void SendResponse(WorldSession* session) const;
-
- void TeleportTo(Player* player) const;
- std::string FormatMessageString(ChatHandler& handler, bool detailed = false) const;
- std::string FormatMessageString(ChatHandler& handler, const char* szClosedName, const char* szAssignedToName, const char* szUnassignedName, const char* szDeletedName, const char* szCompletedName) const;
-
- void SetChatLog(std::list<uint32> time, std::string const& log);
- std::string const& GetChatLog() const { return _chatLog; }
-
-private:
- uint32 _id;
- ObjectGuid _playerGuid;
- std::string _playerName;
- float _posX;
- float _posY;
- float _posZ;
- uint16 _mapId;
- std::string _message;
- uint64 _createTime;
- uint64 _lastModifiedTime;
- ObjectGuid _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it.
- ObjectGuid _assignedTo;
- std::string _comment;
- bool _completed;
- GMTicketEscalationStatus _escalatedStatus;
- bool _viewed;
- bool _needResponse; /// @todo find out the use of this, and then store it in DB
- bool _needMoreHelp;
- std::string _response;
- std::string _chatLog; // No need to store in db, will be refreshed every session client side
-};
-typedef std::map<uint32, GmTicket*> GmTicketList;
-
-class TicketMgr
-{
-private:
- TicketMgr();
- ~TicketMgr();
-
-public:
- static TicketMgr* instance()
- {
- static TicketMgr instance;
- return &instance;
- }
-
- void LoadTickets();
- void LoadSurveys();
-
- GmTicket* GetTicket(uint32 ticketId)
- {
- GmTicketList::iterator itr = _ticketList.find(ticketId);
- if (itr != _ticketList.end())
- return itr->second;
-
- return NULL;
- }
-
- GmTicket* GetTicketByPlayer(ObjectGuid playerGuid)
- {
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- if (itr->second && itr->second->IsFromPlayer(playerGuid) && !itr->second->IsClosed())
- return itr->second;
-
- return NULL;
- }
-
- GmTicket* GetOldestOpenTicket()
- {
- for (GmTicketList::const_iterator itr = _ticketList.begin(); itr != _ticketList.end(); ++itr)
- if (itr->second && !itr->second->IsClosed() && !itr->second->IsCompleted())
- return itr->second;
-
- return NULL;
- }
-
- void AddTicket(GmTicket* ticket);
- void CloseTicket(uint32 ticketId, ObjectGuid source);
- void RemoveTicket(uint32 ticketId);
-
- bool GetStatus() const { return _status; }
- void SetStatus(bool status) { _status = status; }
-
- uint64 GetLastChange() const { return _lastChange; }
- void UpdateLastChange() { _lastChange = uint64(time(NULL)); }
-
- uint32 GenerateTicketId() { return ++_lastTicketId; }
- uint32 GetOpenTicketCount() const { return _openTicketCount; }
- uint32 GetNextSurveyID() { return ++_lastSurveyId; }
-
- void Initialize();
- void ResetTickets();
-
- void ShowList(ChatHandler& handler, bool onlineOnly) const;
- void ShowClosedList(ChatHandler& handler) const;
- void ShowEscalatedList(ChatHandler& handler) const;
-
- void SendTicket(WorldSession* session, GmTicket* ticket) const;
-
-protected:
- void _RemoveTicket(uint32 ticketId, int64 source = -1, bool permanently = false);
-
- GmTicketList _ticketList;
-
- bool _status;
- uint32 _lastTicketId;
- uint32 _lastSurveyId;
- uint32 _openTicketCount;
- uint64 _lastChange;
-};
-
-#define sTicketMgr TicketMgr::instance()
-
-#endif // _TICKETMGR_H
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index c51c9e3ecc4..561cd5bb3a0 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -57,7 +57,7 @@
#include "SkillExtraItems.h"
#include "SmartAI.h"
#include "SystemConfig.h"
-#include "TicketMgr.h"
+#include "SupportMgr.h"
#include "TransportMgr.h"
#include "Unit.h"
#include "VMapFactory.h"
@@ -427,12 +427,22 @@ void World::LoadConfigSettings(bool reload)
SetPlayerAmountLimit(sConfigMgr->GetIntDefault("PlayerLimit", 100));
SetMotd(sConfigMgr->GetStringDefault("Motd", "Welcome to a Trinity Core Server."));
- ///- Read ticket system setting from the config file
- m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS] = sConfigMgr->GetBoolDefault("Ticket.SystemStatus", true);
+ ///- Read support system setting from the config file
+ m_bool_configs[CONFIG_SUPPORT_ENABLED] = sConfigMgr->GetBoolDefault("Support.Enabled", true);
+ m_bool_configs[CONFIG_SUPPORT_TICKETS_ENABLED] = sConfigMgr->GetBoolDefault("Support.TicketsEnabled", false);
+ m_bool_configs[CONFIG_SUPPORT_BUGS_ENABLED] = sConfigMgr->GetBoolDefault("Support.BugsEnabled", false);
+ m_bool_configs[CONFIG_SUPPORT_COMPLAINTS_ENABLED] = sConfigMgr->GetBoolDefault("Support.ComplaintsEnabled", false);
+ m_bool_configs[CONFIG_SUPPORT_SUGGESTIONS_ENABLED] = sConfigMgr->GetBoolDefault("Support.SuggestionsEnabled", false);
if (reload)
- sTicketMgr->SetStatus(m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS]);
- m_bool_configs[CONFIG_TICKET_SUBMIT_TICKET] = sConfigMgr->GetBoolDefault("Ticket.SubmitTicket", false);
- m_bool_configs[CONFIG_TICKET_SUBMIT_BUG] = sConfigMgr->GetBoolDefault("Ticket.SubmitBug", false);
+ {
+ sSupportMgr->SetSupportSystemStatus(m_bool_configs[CONFIG_SUPPORT_ENABLED]);
+ sSupportMgr->SetTicketSystemStatus(m_bool_configs[CONFIG_SUPPORT_TICKETS_ENABLED]);
+ sSupportMgr->SetBugSystemStatus(m_bool_configs[CONFIG_SUPPORT_BUGS_ENABLED]);
+ sSupportMgr->SetComplaintSystemStatus(m_bool_configs[CONFIG_SUPPORT_COMPLAINTS_ENABLED]);
+ sSupportMgr->SetSuggestionSystemStatus(m_bool_configs[CONFIG_SUPPORT_SUGGESTIONS_ENABLED]);
+ }
+ m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfigMgr->GetFloatDefault("Support.ChanceOfGMSurvey", 50.0f);
+
///- Get string for new logins (newly created characters)
SetNewCharString(sConfigMgr->GetStringDefault("PlayerStart.String", ""));
@@ -954,7 +964,6 @@ void World::LoadConfigSettings(bool reload)
}
m_bool_configs[CONFIG_ALLOW_GM_GROUP] = sConfigMgr->GetBoolDefault("GM.AllowInvite", false);
m_bool_configs[CONFIG_GM_LOWER_SECURITY] = sConfigMgr->GetBoolDefault("GM.LowerSecurity", false);
- m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = sConfigMgr->GetFloatDefault("GM.TicketSystem.ChanceOfGMSurvey", 50.0f);
m_int_configs[CONFIG_GROUP_VISIBILITY] = sConfigMgr->GetIntDefault("Visibility.GroupMode", 1);
@@ -1814,10 +1823,19 @@ void World::SetInitialWorldSettings()
sObjectMgr->LoadFactionChangeTitles();
TC_LOG_INFO("server.loading", "Loading GM tickets...");
- sTicketMgr->LoadTickets();
+ sSupportMgr->LoadGmTickets();
+
+ TC_LOG_INFO("server.loading", "Loading GM bugs...");
+ sSupportMgr->LoadBugTickets();
+
+ TC_LOG_INFO("server.loading", "Loading GM complaints...");
+ sSupportMgr->LoadComplaintTickets();
+
+ TC_LOG_INFO("server.loading", "Loading GM suggestions...");
+ sSupportMgr->LoadSuggestionTickets();
- TC_LOG_INFO("server.loading", "Loading GM surveys...");
- sTicketMgr->LoadSurveys();
+ /*TC_LOG_INFO("server.loading", "Loading GM surveys...");
+ sSupportMgr->LoadSurveys();*/
TC_LOG_INFO("server.loading", "Loading client addons...");
AddonMgr::LoadFromDB();
@@ -1916,7 +1934,7 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Starting Arena Season...");
sGameEventMgr->StartArenaSeason();
- sTicketMgr->Initialize();
+ sSupportMgr->Initialize();
///- Initialize Battlegrounds
TC_LOG_INFO("server.loading", "Starting Battleground System");
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 847ca687112..f0cfcb37969 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -151,9 +151,11 @@ enum WorldBoolConfigs
CONFIG_SHOW_MUTE_IN_WORLD,
CONFIG_SHOW_BAN_IN_WORLD,
CONFIG_AUTOBROADCAST,
- CONFIG_TICKET_SYSTEM_STATUS,
- CONFIG_TICKET_SUBMIT_TICKET,
- CONFIG_TICKET_SUBMIT_BUG,
+ CONFIG_SUPPORT_ENABLED,
+ CONFIG_SUPPORT_TICKETS_ENABLED,
+ CONFIG_SUPPORT_BUGS_ENABLED,
+ CONFIG_SUPPORT_COMPLAINTS_ENABLED,
+ CONFIG_SUPPORT_SUGGESTIONS_ENABLED,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_PDUMP_NO_PATHS,