Core/Tickets: Ticket System updated

This commit is contained in:
Yehonal
2016-08-07 12:25:59 +02:00
parent 2ca258e179
commit 444012104b
10 changed files with 115 additions and 19 deletions

View File

@@ -0,0 +1,25 @@
DROP TABLE IF EXISTS `gm_ticket`;
CREATE TABLE IF NOT EXISTS `gm_ticket` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0 open, 1 closed, 2 character deleted',
`playerGuid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier of ticket creator',
`name` varchar(12) NOT NULL COMMENT 'Name of ticket creator',
`description` text NOT NULL,
`createTime` int(10) unsigned NOT NULL DEFAULT '0',
`mapId` smallint(5) unsigned NOT NULL DEFAULT '0',
`posX` float NOT NULL DEFAULT '0',
`posY` float NOT NULL DEFAULT '0',
`posZ` float NOT NULL DEFAULT '0',
`lastModifiedTime` int(10) unsigned NOT NULL DEFAULT '0',
`closedBy` int(10) unsigned NOT NULL DEFAULT '0',
`assignedTo` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'GUID of admin to whom ticket is assigned',
`comment` text NOT NULL,
`response` text NOT NULL,
`completed` tinyint(3) unsigned NOT NULL DEFAULT '0',
`escalated` tinyint(3) unsigned NOT NULL DEFAULT '0',
`viewed` tinyint(3) unsigned NOT NULL DEFAULT '0',
`needMoreHelp` tinyint(3) unsigned NOT NULL DEFAULT '0',
`resolvedBy` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'GUID of GM who resolved the ticket',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10572 DEFAULT CHARSET=utf8 COMMENT='Player System';

View File

@@ -84,6 +84,7 @@
#include "GameObjectAI.h"
#include "PoolMgr.h"
#include "SavingSystem.h"
#include "TicketMgr.h"
#define ZONE_UPDATE_INTERVAL (2*IN_MILLISECONDS)
@@ -4729,6 +4730,11 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
// remove from arena teams
LeaveAllArenaTeams(playerguid);
// close player ticket if any
GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid);
if (ticket)
ticket->SetClosedBy(playerguid);
// remove from group
if (uint32 groupId = GetGroupIdFromStorage(guid))
if (Group* group = sGroupMgr->GetGroupByGUID(groupId))
@@ -4923,9 +4929,18 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
stmt->setUInt32(0, guid);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_GM_TICKETS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
if (sWorld->getBoolConfig(CONFIG_DELETE_CHARACTER_TICKET_TRACE))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION);
stmt->setUInt32(0, guid);
trans->Append(stmt);
}
else
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_GM_TICKETS);
stmt->setUInt32(0, guid);
trans->Append(stmt);
}
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER);
stmt->setUInt32(0, guid);

View File

@@ -32,11 +32,11 @@ inline float GetAge(uint64 t) { return float(time(NULL) - t) / DAY; }
///////////////////////////////////////////////////////////////////////////////////////////////////
// GM ticket
GmTicket::GmTicket() : _id(0), _playerGuid(0), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
_closedBy(0), _assignedTo(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
GmTicket::GmTicket() : _id(0), _type(TICKET_TYPE_OPEN), _playerGuid(0), _posX(0), _posY(0), _posZ(0), _mapId(0), _createTime(0), _lastModifiedTime(0),
_closedBy(0), _resolvedBy(0), _assignedTo(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false),
_needResponse(false), _needMoreHelp(false) { }
GmTicket::GmTicket(Player* player) : _createTime(time(NULL)), _lastModifiedTime(time(NULL)), _closedBy(0), _assignedTo(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), _needMoreHelp(false)
GmTicket::GmTicket(Player* player) : _type(TICKET_TYPE_OPEN), _createTime(time(NULL)), _lastModifiedTime(time(NULL)), _closedBy(0), _resolvedBy(0), _assignedTo(0), _completed(false), _escalatedStatus(TICKET_UNASSIGNED), _viewed(false), _needMoreHelp(false)
{
_id = sTicketMgr->GenerateTicketId();
_playerName = player->GetName();
@@ -47,10 +47,11 @@ 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
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// id, type, playerGuid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket, resolvedBy
uint8 index = 0;
_id = fields[ index].GetUInt32();
_type = TicketType(fields[++index].GetUInt8());
_playerGuid = MAKE_NEW_GUID(fields[++index].GetUInt32(), 0, HIGHGUID_PLAYER);
_playerName = fields[++index].GetString();
_message = fields[++index].GetString();
@@ -68,16 +69,18 @@ bool GmTicket::LoadFromDB(Field* fields)
_escalatedStatus = GMTicketEscalationStatus(fields[++index].GetUInt8());
_viewed = fields[++index].GetBool();
_needMoreHelp = fields[++index].GetBool();
_resolvedBy = fields[++index].GetInt32();
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
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy
uint8 index = 0;
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GM_TICKET);
stmt->setUInt32( index, _id);
stmt->setUInt8(++index, uint8(_type));
stmt->setUInt32(++index, GUID_LOPART(_playerGuid));
stmt->setString(++index, _playerName);
stmt->setString(++index, _message);
@@ -95,6 +98,7 @@ void GmTicket::SaveToDB(SQLTransaction& trans) const
stmt->setUInt8 (++index, uint8(_escalatedStatus));
stmt->setBool (++index, _viewed);
stmt->setBool (++index, _needMoreHelp);
stmt->setInt32(++index, GUID_LOPART(_resolvedBy));
CharacterDatabase.ExecuteOrAppend(trans, stmt);
}
@@ -363,6 +367,20 @@ void TicketMgr::RemoveTicket(uint32 ticketId)
}
}
void TicketMgr::ResolveAndCloseTicket(uint32 ticketId, int64 source)
{
if (GmTicket* ticket = GetTicket(ticketId))
{
SQLTransaction trans = SQLTransaction(nullptr);
ticket->SetClosedBy(source);
ticket->SetResolvedBy(source);
if (source)
--_openTicketCount;
ticket->SaveToDB(trans);
}
}
void TicketMgr::ShowList(ChatHandler& handler, bool onlineOnly) const
{
handler.SendSysMessage(onlineOnly ? LANG_COMMAND_TICKETSHOWONLINELIST : LANG_COMMAND_TICKETSHOWLIST);

View File

@@ -78,6 +78,13 @@ enum LagReportType
LAG_REPORT_TYPE_SPELL = 6
};
enum TicketType
{
TICKET_TYPE_OPEN = 0,
TICKET_TYPE_CLOSED = 1,
TICKET_TYPE_CHARACTER_DELETED = 2,
};
class GmTicket
{
public:
@@ -85,7 +92,7 @@ public:
GmTicket(Player* player);
~GmTicket();
bool IsClosed() const { return _closedBy; }
bool IsClosed() const { return _type != TICKET_TYPE_OPEN; }
bool IsCompleted() const { return _completed; }
bool IsFromPlayer(uint64 guid) const { return guid == _playerGuid; }
bool IsAssigned() const { return _assignedTo != 0; }
@@ -119,7 +126,8 @@ public:
else if (_escalatedStatus == TICKET_UNASSIGNED)
_escalatedStatus = TICKET_ASSIGNED;
}
void SetClosedBy(int64 value) { _closedBy = value; }
void SetClosedBy(int64 value) { _closedBy = value; _type = TICKET_TYPE_CLOSED; }
void SetResolvedBy(int64 value) { _resolvedBy = value; }
void SetCompleted() { _completed = true; }
void SetMessage(std::string const& message)
{
@@ -151,6 +159,7 @@ public:
private:
uint32 _id;
uint64 _playerGuid;
TicketType _type; // 0 = Open, 1 = Closed, 2 = Character deleted
std::string _playerName;
float _posX;
float _posY;
@@ -159,7 +168,8 @@ private:
std::string _message;
uint64 _createTime;
uint64 _lastModifiedTime;
int64 _closedBy; // 0 = Open, -1 = Console, playerGuid = player abandoned ticket, other = GM who closed it.
int64 _closedBy; // 0 = Open or Closed by Console (if type = 1), playerGuid = GM who closed it or player abandoned ticket or read the GM response message.
int64 _resolvedBy; // 0 = Open, -1 = Resolved by Console, GM who resolved it by closing or completing the ticket.
uint64 _assignedTo;
std::string _comment;
bool _completed;
@@ -213,6 +223,7 @@ public:
void AddTicket(GmTicket* ticket);
void CloseTicket(uint32 ticketId, int64 source = -1);
void ResolveAndCloseTicket(uint32 ticketId, int64 source); // used when GM resolves a ticket by simply closing it
void RemoveTicket(uint32 ticketId);
bool GetStatus() const { return _status; }

View File

@@ -443,6 +443,7 @@ void World::LoadConfigSettings(bool reload)
///- Read ticket system setting from the config file
m_bool_configs[CONFIG_ALLOW_TICKETS] = sConfigMgr->GetBoolDefault("AllowTickets", true);
m_bool_configs[CONFIG_DELETE_CHARACTER_TICKET_TRACE] = sConfigMgr->GetBoolDefault("DeletedCharacterTicketTrace", false);
///- Get string for new logins (newly created characters)
SetNewCharString(sConfigMgr->GetStringDefault("PlayerStart.String", ""));
@@ -1043,6 +1044,7 @@ void World::LoadConfigSettings(bool reload)
m_float_configs[CONFIG_LISTEN_RANGE_YELL] = sConfigMgr->GetFloatDefault("ListenRange.Yell", 300.0f);
m_bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetBoolDefault("Battleground.CastDeserter", true);
m_bool_configs[CONFIG_BATTLEGROUND_RANDOM_CROSSFACTION] = sConfigMgr->GetBoolDefault("Battleground.RandomCrossFaction.Enable", true); // [AZTH] RBG Crossfaction
m_bool_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Battleground.QueueAnnouncer.Enable", false);
m_int_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfigMgr->GetIntDefault ("Battleground.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfigMgr->GetIntDefault ("Battleground.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS);

View File

@@ -127,6 +127,7 @@ enum WorldBoolConfigs
CONFIG_DIE_COMMAND_MODE,
CONFIG_DECLINED_NAMES_USED,
CONFIG_BATTLEGROUND_CAST_DESERTER,
CONFIG_BATTLEGROUND_RANDOM_CROSSFACTION, // [AZTH] RBG Crossfaction
CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE,
CONFIG_BG_XP_FOR_KILL,
CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
@@ -143,6 +144,7 @@ enum WorldBoolConfigs
CONFIG_SHOW_KICK_IN_WORLD,
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_WINTERGRASP_ENABLE,

View File

@@ -156,7 +156,7 @@ public:
return true;
}
sTicketMgr->CloseTicket(ticket->GetId(), player ? player->GetGUID() : -1);
sTicketMgr->ResolveAndCloseTicket(ticket->GetId(), player ? player->GetGUID() : -1);
sTicketMgr->UpdateLastChange();
std::string msg = ticket->FormatMessageString(*handler, player ? player->GetName().c_str() : "Console", NULL, NULL, NULL);
@@ -234,8 +234,12 @@ public:
if (Player* player = ticket->GetPlayer())
ticket->SendResponse(player->GetSession());
Player* gm = handler->GetSession() ? handler->GetSession()->GetPlayer() : NULL;
SQLTransaction trans = SQLTransaction(NULL);
ticket->SetCompleted();
ticket->SetResolvedBy(gm ? gm->GetGUID() : -1);
ticket->SaveToDB(trans);
sTicketMgr->UpdateLastChange();

View File

@@ -302,10 +302,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// GM Tickets
PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket FROM gm_tickets", CONNECTION_SYNCH);
PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_tickets (ticketId, guid, name, message, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, haveTicket) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_tickets WHERE ticketId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_tickets WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_ticket WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_ticket WHERE playerGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION, "UPDATE gm_ticket SET type = 2 WHERE playerGuid = ?", CONNECTION_ASYNC);
// GM Survey/subsurvey/lag report
PrepareStatement(CHAR_INS_GM_SURVEY, "INSERT INTO gm_surveys (guid, surveyId, mainSurvey, overallComment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC);
@@ -349,7 +350,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_GROUP_MEMBER_FLAG, "UPDATE group_member SET memberFlags = ? WHERE memberGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_GROUP_DIFFICULTY, "UPDATE groups SET difficulty = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY, "UPDATE groups SET raiddifficulty = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_tickets", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_ticket", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_INVALID_SPELL_TALENTS, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC);

View File

@@ -268,6 +268,7 @@ enum CharacterDatabaseStatements
CHAR_DEL_GM_TICKET,
CHAR_DEL_ALL_GM_TICKETS,
CHAR_DEL_PLAYER_GM_TICKETS,
CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION,
CHAR_INS_GM_SURVEY,
CHAR_INS_GM_SUBSURVEY,

View File

@@ -1407,6 +1407,15 @@ Command.LookupMaxResults = 0
AllowTickets = 1
# DeletedCharacterTicketTrace
# Description: Keep trace of tickets opened by deleted characters
# gm_ticket.playerGuid will be 0, old GUID and character name
# will be included in gm_ticket.comment
# Default: 0 - (Disabled)
# 1 - (Enabled)
DeletedCharacterTicketTrace = 0
#
# DungeonFinder.OptionsMask
# Description: Dungeon and raid finder system.
@@ -2439,6 +2448,14 @@ AutoBroadcast.Timer = 60000
Battleground.CastDeserter = 1
#
# Battleground.RandomCrossFaction.Enable
# Description: Enable random battleground crossfaction randomizing system
# Default: 0 - (Disabled)
# 1 - (Enabled)
Battleground.RandomCrossFaction.Enable = 1
#
# Battleground.QueueAnnouncer.Enable
# Description: Announce battleground queue status to chat.