diff options
| author | silinoron <none@none> | 2010-08-29 20:28:14 -0700 |
|---|---|---|
| committer | silinoron <none@none> | 2010-08-29 20:28:14 -0700 |
| commit | 08205afcc94045c8d74ee4283821db68c5333b1d (patch) | |
| tree | 2d3eff04fe18a1985d08708ed1d79d0a119c4cc6 /src/server/game/Server/Protocol | |
| parent | 1f9936399c6fbd2fe723f1d2e9ceacf463a24f52 (diff) | |
Rewrite much of the GM ticket system
* Extract storage and manipulation of tickets to TicketMgr (from ObjectMgr)
* Extract ticket commands to TicketCommands.cpp
* Adds support for sending GM responses and GM surveys.
* Fix structure of several ticket-related packets.
* Add support for understanding lag reports.
* Thanks Zor for some of the packet structures, and Cyrax for some sniffs
* Please report any issues encountered via the tracker.
--HG--
branch : trunk
Diffstat (limited to 'src/server/game/Server/Protocol')
| -rw-r--r-- | src/server/game/Server/Protocol/Handlers/TicketHandler.cpp | 226 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 4 |
2 files changed, 192 insertions, 38 deletions
diff --git a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp index 7ddf3ca6c91..8d6f8a13294 100644 --- a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp @@ -22,8 +22,11 @@ #include "WorldPacket.h" #include "Common.h" #include "ObjectMgr.h" +#include "TicketMgr.h" #include "Player.h" #include "World.h" +#include "WorldSession.h" +#include "Util.h" void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) { @@ -33,31 +36,32 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) return; } - if (GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) + if (GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) { WorldPacket data(SMSG_GMTICKET_CREATE, 4); - data << uint32(1); // 1 - You already have GM ticket + data << uint32(GMTICKET_RESPONSE_FAILURE); // You already have GM ticket SendPacket(&data); return; } - uint32 map; + uint32 map, unk1; + uint8 needResponse; // ignored float x, y, z; std::string ticketText, ticketText2; SendQueryTimeResponse(); - WorldPacket data(SMSG_GMTICKET_CREATE, 4); recv_data >> map; recv_data >> x; recv_data >> y; recv_data >> z; recv_data >> ticketText; - recv_data >> ticketText2; + recv_data >> unk1; // not sure what this is... replyTo? + recv_data >> needResponse; // always 1/0 -- not sure what retail does with this GM_Ticket *ticket = new GM_Ticket; ticket->name = GetPlayer()->GetName(); - ticket->guid = sObjectMgr.GenerateGMTicketId(); + ticket->guid = sTicketMgr.GenerateGMTicketId(); ticket->playerGuid = GetPlayer()->GetGUID(); ticket->message = ticketText; ticket->createtime = time(NULL); @@ -69,27 +73,29 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) ticket->closed = 0; ticket->assignedToGM = 0; ticket->comment = ""; + ticket->completed = false; + ticket->escalated = TICKET_UNASSIGNED; + ticket->response = ""; - sObjectMgr.AddOrUpdateGMTicket(*ticket, true); + sTicketMgr.AddOrUpdateGMTicket(*ticket, true); - data << uint32(2); + WorldPacket data(SMSG_GMTICKET_CREATE, 4); + data << uint32(GMTICKET_RESPONSE_SUCCESS); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->guid); - } void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) { - WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); - std::string message; recv_data >> message; - GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); if (!ticket) { - data << uint32(1); + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + data << uint32(GMTICKET_RESPONSE_FAILURE); SendPacket(&data); return; } @@ -97,28 +103,28 @@ void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) ticket->message = message; ticket->timestamp = time(NULL); - sObjectMgr.AddOrUpdateGMTicket(*ticket); + sTicketMgr.AddOrUpdateGMTicket(*ticket); - data << uint32(2); + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + data << uint32(GMTICKET_RESPONSE_SUCCESS); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->guid); - } void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) { - GM_Ticket* ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + GM_Ticket* ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); if (ticket) { WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(9); + data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); SendPacket(&data); sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid); - sObjectMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); - SendGMTicketGetTicket(0x0A, 0); + sTicketMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), false); + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); } } @@ -126,36 +132,184 @@ void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) { SendQueryTimeResponse(); - GM_Ticket *ticket = sObjectMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); - if (ticket) - SendGMTicketGetTicket(0x06, ticket->message.c_str()); + if (GM_Ticket *ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID())) + { + if (ticket->completed) + SendGMTicketResponse(ticket); + else + SendGMTicketGetTicket(GMTICKET_STATUS_HASTEXT, ticket->message.c_str(), ticket); + } else - SendGMTicketGetTicket(0x0A, 0); - + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); } void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) { WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); - data << uint32(1); + // are we sure this is a uint32? Should ask Zor + data << uint32(sTicketMgr.GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED); SendPacket(&data); } -void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text) +void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text, GM_Ticket *ticket /* = NULL */) { int len = text ? strlen(text) : 0; - WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4)); + WorldPacket data(SMSG_GMTICKET_GETTICKET, (4+4+((status == GMTICKET_STATUS_HASTEXT) ? (len+1+4+4+4+1+1) : 0))); data << uint32(status); // standard 0x0A, 0x06 if text present - data << uint32(1); // unk flags, if 0, can't edit the ticket - if (status == 6) + data << uint32(1); // g_HasActiveGMTicket -- not a flag + + if (status == GMTICKET_STATUS_HASTEXT) { data << text; // ticket text - data << uint8(0x7); // ticket category - data << float(0); // tickets in queue? - data << float(0); // if > "tickets in queue" then "We are currently experiencing a high volume of petitions." - data << float(0); // 0 - "Your ticket will be serviced soon", 1 - "Wait time currently unavailable" - data << uint8(0); // if == 2 and next field == 1 then "Your ticket has been escalated" - data << uint8(0); // const + data << uint8(0x7); // ticket category; why is this hardcoded? does it make a diff re: client? + + // we've got the easy stuff done by now. + // Now we need to go through the client logic for displaying various levels of ticket load + if (ticket) + { + // get ticketage, but it's stored in seconds so we have to do it in days + float ticketAge = (float)time(NULL) - (float)ticket->timestamp; + ticketAge /= DAY; + + data << float(ticketAge); // ticketAge (days) + if (GM_Ticket *oldestTicket = sTicketMgr.GetOldestOpenGMTicket()) + { + // get ticketage, but it's stored in seconds so we have to do it in days + float oldestTicketAge = (float)time(NULL) - (float)oldestTicket->timestamp; + oldestTicketAge /= DAY; + data << float(oldestTicketAge); + } + else + data << float(0); + + // I am not sure how blizzlike this is, and we don't really have a way to find out + int64 lastChange = int64(sTicketMgr.GetLastChange()); + float timeDiff = float(int64(time(NULL)) - lastChange); + timeDiff /= DAY; + data << float(timeDiff); + + data << uint8(std::min(ticket->escalated, uint8(TICKET_IN_ESCALATION_QUEUE))); // escalated data + data << uint8(ticket->viewed ? GMTICKET_OPENEDBYGM_STATUS_OPENED : GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED); // whether or not it has been viewed + } + else + { + // we can't actually get any numbers here... + data << float(0); + data << float(0); + data << float(1); + data << uint8(0); + data << uint8(0); + } } + + SendPacket(&data); +} + +void WorldSession::SendGMTicketResponse(GM_Ticket *ticket) +{ + if (!ticket) + return; + + WorldPacket data(SMSG_GMRESPONSE_RECEIVED); + data << uint32(1); // unk? Zor says "hasActiveTicket" + data << uint32(0); // can-edit - always 1 or 0, not flags + data << ticket->message.c_str(); + data << ticket->response.c_str(); + for (int8 j = 0; j < 3; j++) + data << uint8(0); // 3 null strings SendPacket(&data); } + +void WorldSession::HandleGMSurveySubmit(WorldPacket& recv_data) +{ + uint64 nextSurveyID = sTicketMgr.GetNextSurveyID(); + // just put the survey into the database + std::ostringstream ss; + uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc + recv_data >> mainSurvey; + + ss << "INSERT INTO gm_surveys (player, surveyid, mainSurvey, overall_comment, timestamp) VALUES ("; + ss << GetPlayer()->GetGUID() << ", "; + ss << nextSurveyID << ", "; + ss << mainSurvey << ", "; + + // 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 < 10; i++) + { + std::ostringstream os; + os << "INSERT INTO gm_subsurveys (surveyid, subsurveyid, rank, comment) VALUES ("; + uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) + recv_data >> subSurveyId; + if(!subSurveyId) + break; + + uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc + std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") + recv_data >> rank; + recv_data >> comment; + + os << nextSurveyID << " "; + os << subSurveyId << ", "; + os << rank << ", '"; + CharacterDatabase.escape_string(comment); + os << comment << "');"; + CharacterDatabase.PExecute(os.str().c_str()); + } + + std::string comment; // just a guess + recv_data >> comment; + CharacterDatabase.escape_string(comment); + ss << "'" << comment << "', "; + ss << int64(time_t(NULL)) << ");"; + + CharacterDatabase.PExecute(ss.str().c_str()); +} + +void WorldSession::HandleReportLag(WorldPacket& recv_data) +{ + // just put the lag report into the database... + // can't think of anything else to do with it + uint32 lagType, mapId; + float x, y, z; + recv_data >> lagType; + recv_data >> mapId; + recv_data >> x; + recv_data >> y; + recv_data >> z; + + // build and execute query + std::ostringstream os; + os << "INSERT INTO lag_reports (player, lag_type, map, x, y, z) VALUES ("; + os << GetPlayer()->GetGUID() << ", "; + os << lagType << ", "; + os << mapId << ", "; + os << x << ", "; + os << y << ", "; + os << z << ");"; + + CharacterDatabase.Execute(os.str().c_str()); +} + +void WorldSession::HandleGMResponseResolve(WorldPacket& recvPacket) +{ + // empty packet + GM_Ticket* ticket = sTicketMgr.GetGMTicketByPlayer(GetPlayer()->GetGUID()); + + if (ticket) + { + uint8 getSurvey = 0; + if ((float)rand_chance() < sWorld.getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY)) + getSurvey = 1; + + WorldPacket data(SMSG_GMRESPONSE_STATUS_UPDATE, 4); + data << uint8(getSurvey); + SendPacket(&data); + + WorldPacket data2(SMSG_GMTICKET_DELETETICKET, 4); + data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + SendPacket(&data2); + sTicketMgr.RemoveGMTicket(ticket, GetPlayer()->GetGUID(), true); + SendGMTicketGetTicket(GMTICKET_STATUS_DEFAULT, NULL); + } +} diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c22148ab96b..f86a7ccba94 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -838,7 +838,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x327*/ { "CMSG_GM_UPDATE_TICKET_STATUS", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x328*/ { "SMSG_GM_TICKET_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x329*/ { "MSG_SET_DUNGEON_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetDungeonDifficultyOpcode}, - /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_NEVER, &WorldSession::Handle_NULL },//LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, + /*0x32A*/ { "CMSG_GMSURVEY_SUBMIT", STATUS_LOGGEDIN, &WorldSession::HandleGMSurveySubmit }, /*0x32B*/ { "SMSG_UPDATE_INSTANCE_OWNERSHIP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x32C*/ { "CMSG_IGNORE_KNOCKBACK_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x32D*/ { "SMSG_CHAT_PLAYER_AMBIGUOUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -1292,7 +1292,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4EE*/ { "SMSG_GMRESPONSE_DB_ERROR", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4EF*/ { "SMSG_GMRESPONSE_RECEIVED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F0*/ { "CMSG_GMRESPONSE_RESOLVE", STATUS_LOGGEDIN, &WorldSession::HandleGMResponseResolve }, /*0x4F1*/ { "SMSG_GMRESPONSE_STATUS_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4F2*/ { "UMSG_UNKNOWN_1266", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4F3*/ { "UMSG_UNKNOWN_1267", STATUS_NEVER, &WorldSession::Handle_NULL }, |
