Skip to content

Commit

Permalink
[z1217] Implement mass mail send infrastructure.
Browse files Browse the repository at this point in the history
It expected to be used in 2 case: some gameevent must send mails at start/end,
and this can be useful in game commands. Both case wil implemented in later commits.

* New MassMailMgr can accept tasks for send mass mails in safe way for map update threads context/etc.
* It work in way:
   - By provided race mask or more generic SQL query string in async query selected affected characters
   - At query result ready at next world tick update in safe common part of tick code some from mails
     from queued mas mail tasks send.
   - Amount mails limited MassMailer.SendPerTick confir option (10 by default). This done for prevent
     high server load/lags at send too many mails in one tick (mail send all existed characters in DB
     who match to seelction criteria)
   - Server wait at shutdown complete mass mail tasks. This is now slowdown shutdown lot:
     with default setting 10K mail send in 20 secs (10000/50/10).
   - But manager not persistant for server crashes so any not send mails in queue lost at crash.

* Implement mass mail gm commands.
  New comamnds mirror related normal sedn commands:
   - send mass items
   - send mass mail
   - send mass money

  Instead player name it expect or numeric racemask or textual race/team name or 'all'.

* Implement game event mail sends at event start/stop.

  Also implement save game event state to DB mostly for avoid
  send mails at resume game event after server downtime.

Thanks to X-Savior for inspiring and original research.

(based on master commit f5c63c4)
(based on master commit 534683c)
(based on master commit 35028c6)
(based on master commit e2e18ec)
(based on master commit 84e29e0)
(based on master commit dbc97cb)
(based on master commit 96df816)

(based on commit 9aea987)
  • Loading branch information
VladimirMangos committed Jan 11, 2011
1 parent 5bb35ae commit 8a6c1a8
Show file tree
Hide file tree
Showing 28 changed files with 859 additions and 59 deletions.
21 changes: 20 additions & 1 deletion sql/characters.sql
Expand Up @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `character_db_version`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_db_version` (
`required_z1142_s0531_01_characters_bugreport` bit(1) default NULL
`required_z1217_s0636_02_characters_game_event_status` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -746,6 +746,25 @@ LOCK TABLES `creature_respawn` WRITE;
/*!40000 ALTER TABLE `creature_respawn` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `game_event_status`
--

DROP TABLE IF EXISTS `game_event_status`;
CREATE TABLE `game_event_status` (
`event` smallint(6) unsigned NOT NULL default '0',
PRIMARY KEY (`event`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Game event system';

--
-- Dumping data for table `game_event_status`
--

LOCK TABLES `game_event_status` WRITE;
/*!40000 ALTER TABLE `game_event_status` DISABLE KEYS */;
/*!40000 ALTER TABLE `game_event_status` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `gameobject_respawn`
--
Expand Down
32 changes: 29 additions & 3 deletions sql/mangos.sql
Expand Up @@ -24,7 +24,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`required_z1205_s0624_01_mangos_mangos_string` bit(1) default NULL
`required_z1217_s0636_03_mangos_game_event_mail` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -651,8 +651,11 @@ INSERT INTO `command` VALUES
('revive',3,'Syntax: .revive\r\n\r\nRevive the selected player. If no player is selected, it will revive you.'),
('save',0,'Syntax: .save\r\n\r\nSaves your character.'),
('saveall',1,'Syntax: .saveall\r\n\r\nSave all characters in game.'),
('send items',3,'Syntax: .send items #playername \"#subject\" \"#text\" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in \"\". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
('send mail',1,'Syntax: .send mail #playername \"#subject\" \"#text\"\r\n\r\nSend a mail to a player. Subject and mail text must be in \"\".'),
('send items',3,'Syntax: .send items #playername "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
('send mail',1,'Syntax: .send mail #playername "#subject" "#text"\r\n\r\nSend a mail to a player. Subject and mail text must be in "".'),
('send mass items',3,'Syntax: .send mass items #racemask|$racename|alliance|horde|all "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to players. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
('send mass mail',1,'Syntax: .send mass mail #racemask|$racename|alliance|horde|all "#subject" "#text"\r\n\r\nSend a mail to players. Subject and mail text must be in "".'),
('send mass money','3','Syntax: .send mass money #racemask|$racename|alliance|horde|all "#subject" "#text" #money\r\n\r\nSend mail with money to players. Subject and mail text must be in "".'),
('send message',3,'Syntax: .send message $playername $message\r\n\r\nSend screen message to player from ADMINISTRATOR.'),
('send money',3,'Syntax: .send money #playername \"#subject\" \"#text\" #money\r\n\r\nSend mail with money to a player. Subject and mail text must be in \"\".'),
('server corpses',2,'Syntax: .server corpses\r\n\r\nTriggering corpses expire check in world.'),
Expand Down Expand Up @@ -1627,6 +1630,29 @@ LOCK TABLES `game_event_gameobject` WRITE;
/*!40000 ALTER TABLE `game_event_gameobject` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `game_event_mail`
--

DROP TABLE IF EXISTS `game_event_mail`;
CREATE TABLE `game_event_mail` (
`event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to send at event stop, positive value for send at event start.',
`raceMask` mediumint(8) unsigned NOT NULL default '0',
`quest` mediumint(8) unsigned NOT NULL default '0',
`mailTemplateId` mediumint(8) unsigned NOT NULL default '0',
`senderEntry` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`event`,`raceMask`,`quest`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Game event system';

--
-- Dumping data for table `game_event_mail`
--

LOCK TABLES `game_event_mail` WRITE;
/*!40000 ALTER TABLE `game_event_mail` DISABLE KEYS */;
/*!40000 ALTER TABLE `game_event_mail` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `game_event_quest`
--
Expand Down
10 changes: 8 additions & 2 deletions sql/updates/Makefile.am
Expand Up @@ -194,7 +194,10 @@ pkgdata_DATA = \
z1192_s0612_02_mangos_spell_chain.sql \
z1194_s0611_01_mangos_mangos_string.sql \
z1202_s0620_01_mangos_mangos_string.sql \
z1205_s0624_01_mangos_mangos_string.sql
z1205_s0624_01_mangos_mangos_string.sql \
z1217_s0636_01_mangos_command.sql \
z1217_s0636_02_characters_game_event_status.sql \
z1217_s0636_03_mangos_game_event_mail.sql

## Additional files to include when running 'make dist'
# SQL update files, to upgrade database schema from older revisions
Expand Down Expand Up @@ -367,4 +370,7 @@ EXTRA_DIST = \
z1192_s0612_02_mangos_spell_chain.sql \
z1194_s0611_01_mangos_mangos_string.sql \
z1202_s0620_01_mangos_mangos_string.sql \
z1205_s0624_01_mangos_mangos_string.sql
z1205_s0624_01_mangos_mangos_string.sql \
z1217_s0636_01_mangos_command.sql \
z1217_s0636_02_characters_game_event_status.sql \
z1217_s0636_03_mangos_game_event_mail.sql
9 changes: 9 additions & 0 deletions sql/updates/z1217_s0636_01_mangos_command.sql
@@ -0,0 +1,9 @@
ALTER TABLE db_version CHANGE COLUMN required_z1205_s0624_01_mangos_mangos_string required_z1217_s0636_01_mangos_command bit;

DELETE FROM command WHERE name IN ('send mass items','send mass mail','send mass money');

INSERT INTO command (name, security, help) VALUES
('send mass items',3,'Syntax: .send mass items #racemask|$racename|alliance|horde|all "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to players. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
('send mass mail',1,'Syntax: .send mass mail #racemask|$racename|alliance|horde|all "#subject" "#text"\r\n\r\nSend a mail to players. Subject and mail text must be in "".'),
('send mass money','3','Syntax: .send mass money #racemask|$racename|alliance|horde|all "#subject" "#text" #money\r\n\r\nSend mail with money to players. Subject and mail text must be in "".');

7 changes: 7 additions & 0 deletions sql/updates/z1217_s0636_02_characters_game_event_status.sql
@@ -0,0 +1,7 @@
ALTER TABLE character_db_version CHANGE COLUMN required_z1142_s0531_01_characters_bugreport required_z1217_s0636_02_characters_game_event_status bit;

DROP TABLE IF EXISTS `game_event_status`;
CREATE TABLE `game_event_status` (
`event` smallint(6) unsigned NOT NULL default '0',
PRIMARY KEY (`event`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Game event system';
11 changes: 11 additions & 0 deletions sql/updates/z1217_s0636_03_mangos_game_event_mail.sql
@@ -0,0 +1,11 @@
ALTER TABLE db_version CHANGE COLUMN required_z1217_s0636_01_mangos_command required_z1217_s0636_03_mangos_game_event_mail bit;

DROP TABLE IF EXISTS `game_event_mail`;
CREATE TABLE `game_event_mail` (
`event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to send at event stop, positive value for send at event start.',
`raceMask` mediumint(8) unsigned NOT NULL default '0',
`quest` mediumint(8) unsigned NOT NULL default '0',
`mailTemplateId` mediumint(8) unsigned NOT NULL default '0',
`senderEntry` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`event`,`raceMask`,`quest`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Game event system';
65 changes: 65 additions & 0 deletions src/game/Chat.cpp
Expand Up @@ -496,8 +496,18 @@ ChatCommand * ChatHandler::getCommandTable()
{ NULL, 0, false, NULL, "", NULL }
};

static ChatCommand sendMassCommandTable[] =
{
{ "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassItemsCommand, "", NULL },
{ "mail", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMailCommand, "", NULL },
{ "money", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMassMoneyCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};

static ChatCommand sendCommandTable[] =
{
{ "mass", SEC_ADMINISTRATOR, true, NULL, "", sendMassCommandTable },

{ "items", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendItemsCommand, "", NULL },
{ "mail", SEC_MODERATOR, true, &ChatHandler::HandleSendMailCommand, "", NULL },
{ "message", SEC_ADMINISTRATOR, true, &ChatHandler::HandleSendMessageCommand, "", NULL },
Expand Down Expand Up @@ -3082,6 +3092,61 @@ uint32 ChatHandler::ExtractAccountId(char** args, std::string* accountName /*= N
return account_id;
}

struct RaceMaskName
{
char const* literal;
uint32 raceMask;
};

static RaceMaskName const raceMaskNames[] =
{
// races
{ "human", (1<<(RACE_HUMAN-1)) },
{ "orc", (1<<(RACE_ORC-1)) },
{ "dwarf", (1<<(RACE_DWARF-1)) },
{ "nightelf", (1<<(RACE_NIGHTELF-1))},
{ "undead", (1<<(RACE_UNDEAD-1)) },
{ "tauren", (1<<(RACE_TAUREN-1)) },
{ "gnome", (1<<(RACE_GNOME-1)) },
{ "troll", (1<<(RACE_TROLL-1)) },

// masks
{ "alliance", RACEMASK_ALLIANCE },
{ "horde", RACEMASK_HORDE },
{ "all", RACEMASK_ALL_PLAYABLE },

// terminator
{ NULL, 0 }
};

bool ChatHandler::ExtractRaceMask(char** text, uint32& raceMask, char const** maskName /*=NULL*/)
{
if (ExtractUInt32(text, raceMask))
{
if (maskName)
*maskName = "custom mask";
}
else
{
for (RaceMaskName const* itr = raceMaskNames; itr->literal; ++itr)
{
if (ExtractLiteralArg(text, itr->literal))
{
raceMask = itr->raceMask;

if (maskName)
*maskName = itr->literal;
break;
}
}

if (!raceMask)
return false;
}

return true;
}

std::string ChatHandler::GetNameLink(Player* chr) const
{
return playerLink(chr->GetName());
Expand Down
11 changes: 11 additions & 0 deletions src/game/Chat.h
Expand Up @@ -36,6 +36,7 @@ class ChatHandler;
class WorldSession;
class WorldPacket;
class GMTicket;
class MailDraft;
class Object;
class GameObject;
class Creature;
Expand Down Expand Up @@ -428,6 +429,10 @@ class ChatHandler
bool HandleSendMessageCommand(char* args);
bool HandleSendMoneyCommand(char* args);

bool HandleSendMassItemsCommand(char* args);
bool HandleSendMassMailCommand(char* args);
bool HandleSendMassMoneyCommand(char* args);

bool HandleServerCorpsesCommand(char* args);
bool HandleServerExitCommand(char* args);
bool HandleServerIdleRestartCommand(char* args);
Expand Down Expand Up @@ -561,6 +566,7 @@ class ChatHandler
ObjectGuid ExtractGuidFromLink(char** text);
GameTele const* ExtractGameTeleFromLink(char** text);
bool ExtractLocationFromLink(char** text, uint32& mapid, float& x, float& y, float& z);
bool ExtractRaceMask(char** text, uint32& raceMask, char const** maskName = NULL);
std::string ExtractPlayerNameFromLink(char** text);
bool ExtractPlayerTarget(char** args, Player** player, ObjectGuid* player_guid = NULL, std::string* player_name = NULL);
// select by arg (name/link) or in-game selection online/offline player
Expand Down Expand Up @@ -591,6 +597,11 @@ class ChatHandler
bool HandleGetValueHelper(Object* target, uint32 field, char* typeStr);
bool HandlerDebugModValueHelper(Object* target, uint32 field, char* typeStr, char* valStr);
bool HandleSetValueHelper(Object* target, uint32 field, char* typeStr, char* valStr);

bool HandleSendItemsHelper(MailDraft& draft, char* args);
bool HandleSendMailHelper(MailDraft& draft, char* args);
bool HandleSendMoneyHelper(MailDraft& draft, char* args);

template<typename T>
void ShowNpcOrGoSpawnInformation(uint32 guid);
template <typename T>
Expand Down

0 comments on commit 8a6c1a8

Please sign in to comment.