aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--patch704
-rw-r--r--sql/base/characters_database.sql12
-rw-r--r--sql/base/world_database.sql5
-rw-r--r--sql/updates/10548_characters_channel.sql8
-rw-r--r--sql/updates/10548_world_command.sql5
-rw-r--r--sql/updates/10548_world_trinity_string.sql4
-rwxr-xr-xsrc/server/game/Chat/Channels/Channel.cpp243
-rwxr-xr-xsrc/server/game/Chat/Channels/Channel.h17
-rwxr-xr-xsrc/server/game/Chat/Chat.cpp4
-rwxr-xr-xsrc/server/game/Chat/Chat.h2
-rwxr-xr-xsrc/server/game/Chat/Commands/Level3.cpp36
-rwxr-xr-xsrc/server/game/Miscellaneous/Language.h4
-rwxr-xr-xsrc/server/game/Server/Protocol/Handlers/ChannelHandler.cpp11
-rwxr-xr-xsrc/server/game/Server/Protocol/Opcodes.cpp2
-rwxr-xr-xsrc/server/game/World/World.cpp6
-rwxr-xr-xsrc/server/game/World/World.h2
-rwxr-xr-xsrc/server/shared/Database/Implementation/CharacterDatabase.cpp7
-rwxr-xr-xsrc/server/shared/Database/Implementation/CharacterDatabase.h6
-rw-r--r--src/server/worldserver/worldserver.conf.dist28
19 files changed, 919 insertions, 187 deletions
diff --git a/patch b/patch
new file mode 100644
index 00000000000..54b189c46be
--- /dev/null
+++ b/patch
@@ -0,0 +1,704 @@
+diff -r 9b294adafcde src/server/game/Chat/Channels/Channel.cpp
+--- a/src/server/game/Chat/Channels/Channel.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Chat/Channels/Channel.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -21,14 +21,17 @@
+ #include "ObjectMgr.h"
+ #include "SocialMgr.h"
+ #include "World.h"
++#include "DatabaseEnv.h"
+
+ Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team)
+- : m_announce(true), m_moderate(false), m_name(name), m_password(""), m_flags(0), m_channelId(channel_id), m_ownerGUID(0), m_Team(Team)
++ : m_announce(true), m_ownership(true), m_name(name), m_password(""), m_flags(0), m_channelId(channel_id), m_ownerGUID(0), m_Team(Team)
+ {
++ m_IsSaved = false;
+ // set special flags if built-in channel
+ if (ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(channel_id)) // check whether it's a built-in channel
+ {
+ m_announce = false; // no join/leave announces
++ m_ownership = false; // no ownership handout
+
+ m_flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels
+
+@@ -42,92 +45,103 @@
+ m_flags |= CHANNEL_FLAG_LFG;
+ else // for all other channels
+ m_flags |= CHANNEL_FLAG_NOT_LFG;
+- m_IsSaved = false;
+ }
+ else // it's custom channel
+ {
+ channel_id = 0;
+ m_flags |= CHANNEL_FLAG_CUSTOM;
++
++ // If storing custom channels in the db is enabled either load or save the channel
++ if (sWorld.getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS))
++ {
++ PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_CHANNEL);
++ stmt->setString(0, name);
++ stmt->setUInt32(1, m_Team);
++ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+
+- //load not built in channel if saved
+- std::string _name(name);
+- CharacterDatabase.escape_string(_name);
+- QueryResult result = CharacterDatabase.PQuery("SELECT m_announce, m_moderate, m_public, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", _name.c_str(), m_Team);
++ if (result) //load
++ {
++ Field *fields = result->Fetch();
++ m_announce = fields[0].GetBool();
++ m_ownership = fields[1].GetBool();
++ m_password = fields[2].GetString();
++ const char* db_BannedList = fields[3].GetCString();
+
+- if (result)//load
+- {
+- Field *fields = result->Fetch();
+- m_announce = fields[0].GetBool();
+- m_moderate = fields[1].GetBool();
+- m_public = fields[2].GetBool();
+- m_password = fields[3].GetString();
+- const char* db_BannedList = fields[4].GetCString();
+-
+- m_IsSaved = true;
+-
+- if (db_BannedList)
+- {
+- Tokens tokens(db_BannedList, ' ');
+- Tokens::iterator iter;
+- for (iter = tokens.begin(); iter != tokens.end(); ++iter)
++ if (db_BannedList)
+ {
+- uint64 banned_guid = atol(*iter);
+- if (banned_guid)
++ Tokens tokens(db_BannedList, ' ');
++ Tokens::iterator iter;
++ for (iter = tokens.begin(); iter != tokens.end(); ++iter)
+ {
+- sLog.outDebug("Channel(%s) loaded banned guid:" UI64FMTD "",name.c_str(), banned_guid);
+- banned.insert(banned_guid);
++ uint64 banned_guid = atol(*iter);
++ if (banned_guid)
++ {
++ sLog.outDebug("Channel(%s) loaded banned guid:" UI64FMTD "",name.c_str(), banned_guid);
++ banned.insert(banned_guid);
++ }
+ }
+ }
+ }
+- }
+- else // save
+- {
+- // _name is already escaped at this point.
+- CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) "
+- "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team);
+- sLog.outDebug("New Channel(%s) saved", name.c_str());
++ else // save
++ {
++ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_CHANNEL);
++ stmt->setString(0, name);
++ stmt->setUInt32(1, m_Team);
++ CharacterDatabase.Execute(stmt);
++ sLog.outDebug("Channel(%s) saved in database", name.c_str());
++ }
++
+ m_IsSaved = true;
+ }
+ }
+ }
+
+-bool Channel::_UpdateStringInDB(const std::string& colName, const std::string& colValue) const
++void Channel::UpdateChannelInDB() const
+ {
+- // Prevent SQL-injection
+- std::string _name(m_name);
+- std::string _colValue(colValue);
+- CharacterDatabase.escape_string(_colValue);
+- CharacterDatabase.escape_string(_name);
+- CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'",
+- colName.c_str(), _colValue.c_str(), _name.c_str(), m_Team);
+- return true;
+-}
+-
+-bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const
+-{
+- // Prevent SQL-injection
+- std::string _name(m_name);
+- CharacterDatabase.escape_string(_name);
+- CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'",
+- colName.c_str(), colValue, _name.c_str(), m_Team);
+- return true;
+-}
+-
+-void Channel::_UpdateBanListInDB() const
+-{
+- // save banlist
+ if (m_IsSaved)
+ {
+ std::ostringstream banlist;
+ BannedList::const_iterator iter;
+ for (iter = banned.begin(); iter != banned.end(); ++iter)
+ banlist << (*iter) << " ";
++
+ std::string banListStr = banlist.str();
+- if (_UpdateStringInDB("BannedList", banListStr))
+- sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str());
++
++ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_CHANNEL);
++ stmt->setBool(0, m_announce);
++ stmt->setBool(1, m_ownership);
++ stmt->setString(2, m_password);
++ stmt->setString(3, banListStr);
++ stmt->setString(4, m_name);
++ stmt->setUInt32(5, m_Team);
++ CharacterDatabase.Execute(stmt);
++
++ sLog.outDebug("Channel(%s) updated in database", m_name.c_str());
++ }
++
++}
++
++void Channel::UpdateChannelUseageInDB() const
++{
++ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_CHANNEL_USAGE);
++ stmt->setString(0, m_name);
++ stmt->setUInt32(1, m_Team);
++ CharacterDatabase.Execute(stmt);
++}
++
++void Channel::CleanOldChannelsInDB()
++{
++ if (sWorld.getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION) > 0)
++ {
++ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_CHANNEL);
++ stmt->setUInt32(0, sWorld.getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION)*DAY);
++ CharacterDatabase.Execute(stmt);
++
++ sLog.outDebug("Cleaned out unused custom chat channels.");
+ }
+ }
+
++
+ void Channel::Join(uint64 p, const char *pass)
+ {
+ WorldPacket data;
+@@ -188,18 +202,20 @@
+
+ JoinNotify(p);
+
+- // if no owner first logged will become
+- if (!IsConstant() && !m_ownerGUID)
++ // Custom channel handling
++ if (!IsConstant())
+ {
+- SetOwner(p, (players.size() > 1 ? true : false));
+- players[p].SetModerator(true);
++ // Update last_used timestamp in db
++ if(!players.empty())
++ UpdateChannelUseageInDB();
++
++ // If the channel has no owner yet and ownership is allowed, set the new owner.
++ if ( !m_ownerGUID && m_ownership)
++ {
++ SetOwner(p, (players.size() > 1 ? true : false));
++ players[p].SetModerator(true);
++ }
+ }
+- /*
+- else if (!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID()))
+- {
+- SetOwner(p, (players.size() > 1 ? true : false));
+- players[p].SetModerator(true);
+- }*/
+ }
+
+ void Channel::Leave(uint64 p, bool send)
+@@ -239,11 +255,18 @@
+
+ LeaveNotify(p);
+
+- if (changeowner)
++ if (!IsConstant())
+ {
+- uint64 newowner = !players.empty() ? players.begin()->second.player : 0;
+- players[newowner].SetModerator(true);
+- SetOwner(newowner);
++ // Update last_used timestamp in db
++ UpdateChannelUseageInDB();
++
++ // If the channel owner left and there are still players inside, pick a new owner
++ if (changeowner && m_ownership && !players.empty())
++ {
++ uint64 newowner = players.begin()->second.player;
++ players[newowner].SetModerator(true);
++ SetOwner(newowner);
++ }
+ }
+ }
+ }
+@@ -292,8 +315,8 @@
+ {
+ banned.insert(bad->GetGUID());
+ MakePlayerBanned(&data, bad->GetGUID(), good);
+- _UpdateBanListInDB();
+
++ UpdateChannelInDB();
+ }
+ else
+ MakePlayerKicked(&data, bad->GetGUID(), good);
+@@ -302,9 +325,9 @@
+ players.erase(bad->GetGUID());
+ bad->LeftChannel(this);
+
+- if (changeowner)
++ if (changeowner && m_ownership && !players.empty())
+ {
+- uint64 newowner = !players.empty() ? good : false;
++ uint64 newowner = good;
+ players[newowner].SetModerator(true);
+ SetOwner(newowner);
+ }
+@@ -347,8 +370,8 @@
+ WorldPacket data;
+ MakePlayerUnbanned(&data, bad->GetGUID(), good);
+ SendToAll(&data);
+- //save banlist
+- _UpdateBanListInDB();
++
++ UpdateChannelInDB();
+ }
+ }
+ }
+@@ -363,12 +386,6 @@
+
+ ChatHandler chat(plr);
+
+- if (!m_public && sec <= SEC_MODERATOR)
+- {
+- chat.PSendSysMessage(LANG_CHANNEL_NOT_PUBLIC);
+- return;
+- }
+-
+ if (!IsOn(p))
+ {
+ WorldPacket data;
+@@ -388,8 +405,8 @@
+ WorldPacket data;
+ MakePasswordChanged(&data, p);
+ SendToAll(&data);
+- if (m_IsSaved && _UpdateStringInDB("m_password", m_password))
+- sLog.outDebug("Channel(%s) password saved", m_name.c_str());
++
++ UpdateChannelInDB();
+ }
+ }
+
+@@ -595,43 +612,8 @@
+ else
+ MakeAnnouncementsOff(&data, p);
+ SendToAll(&data);
+- if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0))
+- sLog.outDebug("Channel(%s) announce saved", m_name.c_str());
+
+- }
+-}
+-
+-void Channel::Moderate(uint64 p)
+-{
+- uint32 sec = 0;
+- Player *plr = sObjectMgr.GetPlayer(p);
+- if (plr)
+- sec = plr->GetSession()->GetSecurity();
+-
+- if (!IsOn(p))
+- {
+- WorldPacket data;
+- MakeNotMember(&data);
+- SendToOne(&data, p);
+- }
+- else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER)
+- {
+- WorldPacket data;
+- MakeNotModerator(&data);
+- SendToOne(&data, p);
+- }
+- else
+- {
+- m_moderate = !m_moderate;
+-
+- WorldPacket data;
+- if (m_moderate)
+- MakeModerationOn(&data, p);
+- else
+- MakeModerationOff(&data, p);
+- SendToAll(&data);
+- if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0))
+- sLog.outDebug("Channel(%s) announce saved", m_name.c_str());
++ UpdateChannelInDB();
+ }
+ }
+
+@@ -659,7 +641,7 @@
+ MakeMuted(&data);
+ SendToOne(&data, p);
+ }
+- else if (m_moderate && !players[p].IsModerator() && sec < SEC_GAMEMASTER)
++ else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER)
+ {
+ WorldPacket data;
+ MakeNotModerator(&data);
+@@ -768,9 +750,8 @@
+ MakeOwnerChanged(&data, m_ownerGUID);
+ SendToAll(&data);
+ }
+- if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0))
+- sLog.outDebug("Channel(%s) moderate saved", m_name.c_str());
+
++ UpdateChannelInDB();
+ }
+ }
+
+@@ -936,20 +917,6 @@
+ *data << uint64(guid);
+ }
+
+-// done 0x0F
+-void Channel::MakeModerationOn(WorldPacket *data, uint64 guid)
+-{
+- MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE);
+- *data << uint64(guid);
+-}
+-
+-// done 0x10
+-void Channel::MakeModerationOff(WorldPacket *data, uint64 guid)
+-{
+- MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE);
+- *data << uint64(guid);
+-}
+-
+ // done 0x11
+ void Channel::MakeMuted(WorldPacket *data)
+ {
+diff -r 9b294adafcde src/server/game/Chat/Channels/Channel.h
+--- a/src/server/game/Chat/Channels/Channel.h Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Chat/Channels/Channel.h Thu Dec 02 03:14:06 2010 +0100
+@@ -48,8 +48,8 @@
+ CHAT_MODE_CHANGE_NOTICE = 0x0C, //?
+ CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s.";
+ CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s.";
+- CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
+- CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
++ // CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
++ // CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
+ CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak.";
+ CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s.";
+ CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel.";
+@@ -150,8 +150,7 @@
+ typedef std::set<uint64> BannedList;
+ BannedList banned;
+ bool m_announce;
+- bool m_moderate;
+- bool m_public;
++ bool m_ownership;
+ std::string m_name;
+ std::string m_password;
+ uint8 m_flags;
+@@ -178,8 +177,6 @@
+ void MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags); //+ 0x0C
+ void MakeAnnouncementsOn(WorldPacket *data, uint64 guid); //+ 0x0D
+ void MakeAnnouncementsOff(WorldPacket *data, uint64 guid); //+ 0x0E
+- void MakeModerationOn(WorldPacket *data, uint64 guid); //+ 0x0F
+- void MakeModerationOff(WorldPacket *data, uint64 guid); //+ 0x10
+ void MakeMuted(WorldPacket *data); //? 0x11
+ void MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good); //? 0x12
+ void MakeBanned(WorldPacket *data); //? 0x13
+@@ -207,9 +204,8 @@
+ bool IsOn(uint64 who) const { return players.find(who) != players.end(); }
+ bool IsBanned(uint64 guid) const { return banned.find(guid) != banned.end(); }
+
+- bool _UpdateStringInDB(const std::string& colName, const std::string& colValue) const;
+- bool _UpdateIntInDB(const std::string& colName, int colValue) const;
+- void _UpdateBanListInDB() const;
++ void UpdateChannelInDB() const;
++ void UpdateChannelUseageInDB() const;
+
+ uint8 GetPlayerFlags(uint64 p) const
+ {
+@@ -278,13 +274,14 @@
+ void UnsetMute(uint64 p, const char *newname) { SetMode(p, newname, false, false); }
+ void List(Player* p);
+ void Announce(uint64 p);
+- void Moderate(uint64 p);
+ void Say(uint64 p, const char *what, uint32 lang);
+ void Invite(uint64 p, const char *newp);
+ void Voice(uint64 guid1, uint64 guid2);
+ void DeVoice(uint64 guid1, uint64 guid2);
+ void JoinNotify(uint64 guid); // invisible notify
+ void LeaveNotify(uint64 guid); // invisible notify
++ void SetOwnership(bool ownership) { m_ownership = ownership; };
++ static void CleanOldChannelsInDB();
+ };
+ #endif
+
+diff -r 9b294adafcde src/server/game/Chat/Chat.cpp
+--- a/src/server/game/Chat/Chat.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Chat/Chat.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -150,8 +150,8 @@
+
+ static ChatCommand channelSetCommandTable[] =
+ {
+- { "public", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleChannelSetPublic>, "", NULL },
+- { NULL, 0, false, NULL, "", NULL }
++ { "ownership", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleChannelSetOwnership>, "", NULL },
++ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand channelCommandTable[] =
+diff -r 9b294adafcde src/server/game/Chat/Chat.h
+--- a/src/server/game/Chat/Chat.h Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Chat/Chat.h Thu Dec 02 03:14:06 2010 +0100
+@@ -166,7 +166,7 @@
+ bool HandleCharacterReputationCommand(const char* args);
+ bool HandleCharacterTitlesCommand(const char* args);
+
+- bool HandleChannelSetPublic(const char *args);
++ bool HandleChannelSetOwnership(const char *args);
+
+ bool HandlePossessCommand(const char* args);
+ bool HandleUnPossessCommand(const char* args);
+diff -r 9b294adafcde src/server/game/Chat/Commands/Level3.cpp
+--- a/src/server/game/Chat/Commands/Level3.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Chat/Commands/Level3.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -61,6 +61,7 @@
+ #include "CreatureTextMgr.h"
+ #include "SmartAI.h"
+ #include "Group.h"
++#include "ChannelMgr.h"
+
+ bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/)
+ {
+@@ -4400,25 +4401,38 @@
+ return true;
+ }
+
+-bool ChatHandler::HandleChannelSetPublic(const char *args)
++bool ChatHandler::HandleChannelSetOwnership(const char *args)
+ {
+ if (!*args)
+ return false;
+- std::string channel = strtok((char*)args, " ");
+- uint32 val = atoi((char*)args);
+-
+- if (val)
++ char *channel = strtok((char*)args, " ");
++ char *argstr = strtok(NULL, "");
++
++ if (!channel || !argstr)
++ return false;
++
++ Player *player = m_session->GetPlayer();
++ Channel *chn;
++
++ if (ChannelMgr* cMgr = channelMgr(player->GetTeam()))
++ chn = cMgr->GetChannel(channel, player);
++
++ if (strcmp(argstr, "on") == 0)
+ {
+- CharacterDatabase.PExecute("UPDATE channels SET m_public = 1 WHERE m_name LIKE '%s'", channel.c_str());
+- val = 1;
++ if(chn)
++ chn->SetOwnership(true);
++ CharacterDatabase.PExecute("UPDATE channels SET m_ownership = 1 WHERE m_name LIKE '%s'", channel);
++ PSendSysMessage(LANG_CHANNEL_ENABLE_OWNERSHIP, channel);
++ }
++ else if (strcmp(argstr, "off") == 0)
++ {
++ if(chn)
++ chn->SetOwnership(false);
++ CharacterDatabase.PExecute("UPDATE channels SET m_ownership = 0 WHERE m_name LIKE '%s'", channel);
++ PSendSysMessage(LANG_CHANNEL_DISABLE_OWNERSHIP, channel);
+ }
+ else
+- {
+- CharacterDatabase.PExecute("UPDATE channels SET m_public = 0 WHERE m_name LIKE '%s'", channel.c_str());
+- val = 0;
+- }
+-
+- PSendSysMessage(LANG_CHANNEL_PUBLIC_CHANGED, channel.c_str(), val);
++ return false;
+
+ return true;
+ }
+diff -r 9b294adafcde src/server/game/Miscellaneous/Language.h
+--- a/src/server/game/Miscellaneous/Language.h Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Miscellaneous/Language.h Thu Dec 02 03:14:06 2010 +0100
+@@ -906,8 +906,8 @@
+ LANG_MOUNTABLE = 5019,
+ LANG_NPCINFO_PHASEMASK = 5020,
+ LANG_NPCINFO_ARMOR = 5021,
+- LANG_CHANNEL_NOT_PUBLIC = 5022,
+- LANG_CHANNEL_PUBLIC_CHANGED = 5023,
++ LANG_CHANNEL_ENABLE_OWNERSHIP = 5022,
++ LANG_CHANNEL_DISABLE_OWNERSHIP = 5023,
+ LANG_GOINFO_ENTRY = 5024,
+ LANG_GOINFO_TYPE = 5025,
+ LANG_GOINFO_DISPLAYID = 5026,
+diff -r 9b294adafcde src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp
+--- a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -281,17 +281,6 @@
+ chn->Announce(_player->GetGUID());
+ }
+
+-void WorldSession::HandleChannelModerate(WorldPacket& recvPacket)
+-{
+- sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
+- //recvPacket.hexlike();
+- std::string channelname;
+- recvPacket >> channelname;
+- if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
+- if (Channel *chn = cMgr->GetChannel(channelname, _player))
+- chn->Moderate(_player->GetGUID());
+-}
+-
+ void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket)
+ {
+ sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
+diff -r 9b294adafcde src/server/game/Server/Protocol/Opcodes.cpp
+--- a/src/server/game/Server/Protocol/Opcodes.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/Server/Protocol/Opcodes.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -194,7 +194,7 @@
+ /*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan },
+ /*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban },
+ /*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnouncements },
+- /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate },
++ /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_NEVER, &WorldSession::Handle_NULL },
+ /*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
+ /*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode },
+diff -r 9b294adafcde src/server/game/World/World.cpp
+--- a/src/server/game/World/World.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/World/World.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -71,6 +71,7 @@
+ #include "WeatherMgr.h"
+ #include "CreatureTextMgr.h"
+ #include "SmartAI.h"
++#include "Channel.h"
+
+ volatile bool World::m_stopEvent = false;
+ uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
+@@ -576,6 +577,8 @@
+ m_int_configs[CONFIG_AUCTION_LEVEL_REQ] = sConfig.GetIntDefault("LevelReq.Auction", 1);
+ m_int_configs[CONFIG_MAIL_LEVEL_REQ] = sConfig.GetIntDefault("LevelReq.Mail", 1);
+ m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = sConfig.GetBoolDefault("AllowPlayerCommands", 1);
++ m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = sConfig.GetBoolDefault("PreserveCustomChannels", false);
++ m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = sConfig.GetIntDefault("PreserveCustomChannelDuration", 14);
+ m_bool_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true);
+ m_int_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILLISECONDS);
+ m_int_configs[CONFIG_INTERVAL_DISCONNECT_TOLERANCE] = sConfig.GetIntDefault("DisconnectToleranceInterval", 0);
+@@ -1673,6 +1676,9 @@
+ // Delete all characters which have been deleted X days before
+ Player::DeleteOldCharacters();
+
++ // Delete all custom channels which haven't been used for PreserveCustomChannelDuration days.
++ Channel::CleanOldChannelsInDB();
++
+ sLog.outString("Starting Arena Season...");
+ sGameEventMgr.StartArenaSeason();
+
+diff -r 9b294adafcde src/server/game/World/World.h
+--- a/src/server/game/World/World.h Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/game/World/World.h Thu Dec 02 03:14:06 2010 +0100
+@@ -163,6 +163,7 @@
+ CONFIG_AUTOBROADCAST,
+ CONFIG_ALLOW_TICKETS,
+ CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
++ CONFIG_PRESERVE_CUSTOM_CHANNELS,
+ BOOL_CONFIG_VALUE_COUNT
+ };
+
+@@ -308,6 +309,7 @@
+ CONFIG_AUTOBROADCAST_INTERVAL,
+ CONFIG_MAX_RESULTS_LOOKUP_COMMANDS,
+ CONFIG_DB_PING_INTERVAL,
++ CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION,
+ INT_CONFIG_VALUE_COUNT
+ };
+
+diff -r 9b294adafcde src/server/shared/Database/Implementation/CharacterDatabase.cpp
+--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp Thu Dec 02 03:14:06 2010 +0100
+@@ -215,5 +215,12 @@
+ PrepareStatement(CHAR_DEL_CRESPAWNTIME, "DELETE FROM creature_respawn WHERE guid = ? AND instance = ?");
+ PrepareStatement(CHAR_ADD_CRESPAWNTIME, "INSERT INTO creature_respawn VALUES (?, ?, ?)");
+
++ // Chat channel handling
++ PrepareStatement(CHAR_LOAD_CHANNEL, "SELECT m_announce, m_ownership, m_password, BannedList FROM channels WHERE m_name = ? AND m_team = ?");
++ PrepareStatement(CHAR_ADD_CHANNEL, "INSERT INTO channels (m_name, m_team, last_used) VALUES (? , ?, UNIX_TIMESTAMP())");
++ PrepareStatement(CHAR_SET_CHANNEL, "UPDATE channels SET m_announce = ?, m_ownership = ?, m_password = ?, BannedList = ?, last_used = UNIX_TIMESTAMP() WHERE m_name = ? AND m_team = ?");
++ PrepareStatement(CHAR_SET_CHANNEL_USAGE, "UPDATE channels SET last_used = UNIX_TIMESTAMP() WHERE m_name = ? AND m_team = ?");
++ PrepareStatement(CHAR_CLEAN_CHANNEL, "DELETE FROM channels WHERE m_ownership = 1 AND (last_used + ?) < UNIX_TIMESTAMP()");
++
+ return true;
+ }
+diff -r 9b294adafcde src/server/shared/Database/Implementation/CharacterDatabase.h
+--- a/src/server/shared/Database/Implementation/CharacterDatabase.h Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/shared/Database/Implementation/CharacterDatabase.h Thu Dec 02 03:14:06 2010 +0100
+@@ -181,6 +181,12 @@
+ CHAR_DEL_CRESPAWNTIME,
+ CHAR_ADD_CRESPAWNTIME,
+
++ CHAR_LOAD_CHANNEL,
++ CHAR_ADD_CHANNEL,
++ CHAR_SET_CHANNEL,
++ CHAR_SET_CHANNEL_USAGE,
++ CHAR_CLEAN_CHANNEL,
++
+ MAX_CHARACTERDATABASE_STATEMENTS,
+ };
+
+diff -r 9b294adafcde src/server/worldserver/worldserver.conf.dist
+--- a/src/server/worldserver/worldserver.conf.dist Wed Dec 01 21:20:28 2010 +0200
++++ b/src/server/worldserver/worldserver.conf.dist Thu Dec 02 03:14:06 2010 +0100
+@@ -1371,9 +1371,10 @@
+
+ #
+ # DBC.EnforceItemAttributes
+-# Disallow overriding item attributes stored in DBC files with values from the database
+-# Default: 0 - Off, Use DB values
+-# 1 - On, Enforce DBC Values (default)
++# Description: Disallow overriding item attributes stored in DBC files with values from the
++# database.
++# Default: 1 - (Enabled, Enforce DBC values)
++# 0 - (Disabled, Use database values)
+
+ DBC.EnforceItemAttributes = 1
+
+@@ -1745,6 +1746,27 @@
+ AllowPlayerCommands = 1
+
+ #
++# PreserveCustomChannels
++# Description: Store custom chat channel settings like password, automatic ownership handout
++# or ban list in the database. Needs to be enabled to save custom
++# world/trade/etc. channels that have automatic ownership handout disabled.
++# (.channel set ownership $channel off)
++# Default: 0 - (Disabled, Blizzlike, Channel settings are lost if last person left)
++# 1 - (Enabled)
++
++PreserveCustomChannels = 1
++
++#
++# PreserveCustomChannelDuration
++# Description: Time (in days) that needs to pass before the customs chat channels get
++# cleaned up from the database. Only channels with ownership handout enabled
++# (default behavior) will be cleaned.
++# Default: 14 - (Enabled, Clean channels that haven't been used for 14 days)
++# 0 - (Disabled, Infinite channel storage)
++
++PreserveCustomChannelDuration = 14
++
++#
+ ###################################################################################################
+
+ ###################################################################################################
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index 96a59021971..3753593e694 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -238,14 +238,14 @@ DROP TABLE IF EXISTS `channels`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `channels` (
- `m_name` text NOT NULL,
+ `m_name` varchar(128) NOT NULL,
`m_team` int(10) unsigned NOT NULL,
- `m_announce` tinyint(1) unsigned NOT NULL default '0',
- `m_moderate` tinyint(1) unsigned NOT NULL default '0',
- `m_public` tinyint(1) unsigned NOT NULL default '1',
- `m_password` text,
+ `m_announce` tinyint(3) unsigned NOT NULL default '1',
+ `m_ownership` tinyint(3) unsigned NOT NULL default '1',
+ `m_password` varchar(32) NULL,
`BannedList` longtext,
- PRIMARY KEY (`m_name`(10),`m_team`)
+ `last_used` INT(10) UNSIGNED NOT NULL,
+ PRIMARY KEY (`m_name`,`m_team`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Channel System';
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/sql/base/world_database.sql b/sql/base/world_database.sql
index 7e0a4e0cc45..94079a37c6d 100644
--- a/sql/base/world_database.sql
+++ b/sql/base/world_database.sql
@@ -366,6 +366,7 @@ INSERT INTO `command` VALUES
('character titles',2,'Syntax: .character titles [$player_name]\r\n\r\nShow known titles list for selected player or player find by $player_name.'),
('character changefaction',2,'Syntax: .character changefaction $name\r\n\r\nChange character faction.'),
('character changerace',2,'Syntax: .character changerace $name\r\n\r\nChange character race.'),
+('channel set ownership', 3, 'Syntax: .channel set ownership $channel [on/off]\n\n\Grant ownership to the first person that joins the channel.'),
('channel set public', 3, 'Syntax: .channel set public $channel $public\r\n\r\nChange password-changing ability for a channel. 1 for possible, 0 for GM only.'),
('combatstop',2,'Syntax: .combatstop [$playername]\r\nStop combat for selected character. If selected non-player then command applied to self. If $playername provided then attempt applied to online player $playername.'),
('cometome',3,'SYntax: .cometome $parameter\nMake selected creature come to your current location (new position not saved to DB).'),
@@ -27744,8 +27745,8 @@ INSERT INTO `trinity_string` (`entry`,`content_default`,`content_loc1`,`content_
(5019, '[Mountable]', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(5020, 'Phasemask: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(5021, 'Armor: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
-(5022, 'Channel password not changed due to channel being marked public. GM Powers required.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
-(5023, 'Channel: %s publicity set to: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+(5022, 'Granting ownership to first person that joins the channel \"%s\": Enabled.'),
+(5023, 'Granting ownership to first person that joins the channel \"%s\": Disabled.'),
(5024, 'Entry: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(5025, 'Type: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(5026, 'DisplayID: %u', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
diff --git a/sql/updates/10548_characters_channel.sql b/sql/updates/10548_characters_channel.sql
new file mode 100644
index 00000000000..905d3583e4a
--- /dev/null
+++ b/sql/updates/10548_characters_channel.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `channels`
+DROP COLUMN `m_moderate`,
+CHANGE `m_name` `m_name` VARCHAR(128) NOT NULL,
+CHANGE `m_announce` `m_announce` TINYINT(3) UNSIGNED DEFAULT '1' NOT NULL,
+CHANGE `m_public` `m_ownership` TINYINT(3) UNSIGNED DEFAULT '1' NOT NULL,
+CHANGE `m_password` `m_password` VARCHAR(32) NULL,
+ADD COLUMN `last_used` INT(10) UNSIGNED NOT NULL AFTER `BannedList`;
+SET last_used = UNIX_TIMESTAMP();
diff --git a/sql/updates/10548_world_command.sql b/sql/updates/10548_world_command.sql
new file mode 100644
index 00000000000..8ea3ddbbc9e
--- /dev/null
+++ b/sql/updates/10548_world_command.sql
@@ -0,0 +1,5 @@
+DELETE FROM `command` WHERE `name` LIKE 'channel set public';
+DELETE FROM `command` WHERE `name` LIKE 'channel set ownership';
+INSERT INTO `command` (`name`,`security`,`help`) VALUES
+('channel set ownership', 3, 'Syntax: .channel set ownership $channel [on/off]\n\n\Grant ownership to the first person that joins the channel.');
+
diff --git a/sql/updates/10548_world_trinity_string.sql b/sql/updates/10548_world_trinity_string.sql
new file mode 100644
index 00000000000..2bc5147133b
--- /dev/null
+++ b/sql/updates/10548_world_trinity_string.sql
@@ -0,0 +1,4 @@
+DELETE FROM `trinity_string` WHERE `entry` IN (5022, 5023);
+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
+(5022, 'Granting ownership to first person that joins the channel \"%s\": Enabled.'),
+(5023, 'Granting ownership to first person that joins the channel \"%s\": Disabled.');
diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp
index 2690a7ab149..9a5e42ef6c0 100755
--- a/src/server/game/Chat/Channels/Channel.cpp
+++ b/src/server/game/Chat/Channels/Channel.cpp
@@ -21,14 +21,17 @@
#include "ObjectMgr.h"
#include "SocialMgr.h"
#include "World.h"
+#include "DatabaseEnv.h"
Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team)
- : m_announce(true), m_moderate(false), m_name(name), m_password(""), m_flags(0), m_channelId(channel_id), m_ownerGUID(0), m_Team(Team)
+ : m_announce(true), m_ownership(true), m_name(name), m_password(""), m_flags(0), m_channelId(channel_id), m_ownerGUID(0), m_Team(Team)
{
+ m_IsSaved = false;
// set special flags if built-in channel
if (ChatChannelsEntry const* ch = sChatChannelsStore.LookupEntry(channel_id)) // check whether it's a built-in channel
{
m_announce = false; // no join/leave announces
+ m_ownership = false; // no ownership handout
m_flags |= CHANNEL_FLAG_GENERAL; // for all built-in channels
@@ -42,92 +45,103 @@ Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team)
m_flags |= CHANNEL_FLAG_LFG;
else // for all other channels
m_flags |= CHANNEL_FLAG_NOT_LFG;
- m_IsSaved = false;
}
else // it's custom channel
{
channel_id = 0;
m_flags |= CHANNEL_FLAG_CUSTOM;
-
- //load not built in channel if saved
- std::string _name(name);
- CharacterDatabase.escape_string(_name);
- QueryResult result = CharacterDatabase.PQuery("SELECT m_announce, m_moderate, m_public, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", _name.c_str(), m_Team);
-
- if (result)//load
+
+ // If storing custom channels in the db is enabled either load or save the channel
+ if (sWorld.getBoolConfig(CONFIG_PRESERVE_CUSTOM_CHANNELS))
{
- Field *fields = result->Fetch();
- m_announce = fields[0].GetBool();
- m_moderate = fields[1].GetBool();
- m_public = fields[2].GetBool();
- m_password = fields[3].GetString();
- const char* db_BannedList = fields[4].GetCString();
-
- m_IsSaved = true;
+ PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_CHANNEL);
+ stmt->setString(0, name);
+ stmt->setUInt32(1, m_Team);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
- if (db_BannedList)
+ if (result) //load
{
- Tokens tokens(db_BannedList, ' ');
- Tokens::iterator iter;
- for (iter = tokens.begin(); iter != tokens.end(); ++iter)
+ Field *fields = result->Fetch();
+ m_announce = fields[0].GetBool();
+ m_ownership = fields[1].GetBool();
+ m_password = fields[2].GetString();
+ const char* db_BannedList = fields[3].GetCString();
+
+ if (db_BannedList)
{
- uint64 banned_guid = atol(*iter);
- if (banned_guid)
+ Tokens tokens(db_BannedList, ' ');
+ Tokens::iterator iter;
+ for (iter = tokens.begin(); iter != tokens.end(); ++iter)
{
- sLog.outDebug("Channel(%s) loaded banned guid:" UI64FMTD "",name.c_str(), banned_guid);
- banned.insert(banned_guid);
+ uint64 banned_guid = atol(*iter);
+ if (banned_guid)
+ {
+ sLog.outDebug("Channel(%s) loaded banned guid:" UI64FMTD "",name.c_str(), banned_guid);
+ banned.insert(banned_guid);
+ }
}
}
}
- }
- else // save
- {
- // _name is already escaped at this point.
- CharacterDatabase.PExecute("INSERT INTO channels (m_name, m_team, m_announce, m_moderate, m_public, m_password) "
- "VALUES ('%s', '%u', '1', '0', '1', '')", _name.c_str(), m_Team);
- sLog.outDebug("New Channel(%s) saved", name.c_str());
+ else // save
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_CHANNEL);
+ stmt->setString(0, name);
+ stmt->setUInt32(1, m_Team);
+ CharacterDatabase.Execute(stmt);
+ sLog.outDebug("Channel(%s) saved in database", name.c_str());
+ }
+
m_IsSaved = true;
}
}
}
-bool Channel::_UpdateStringInDB(const std::string& colName, const std::string& colValue) const
+void Channel::UpdateChannelInDB() const
{
- // Prevent SQL-injection
- std::string _name(m_name);
- std::string _colValue(colValue);
- CharacterDatabase.escape_string(_colValue);
- CharacterDatabase.escape_string(_name);
- CharacterDatabase.PExecute("UPDATE channels SET %s = '%s' WHERE m_name = '%s' AND m_team = '%u'",
- colName.c_str(), _colValue.c_str(), _name.c_str(), m_Team);
- return true;
-}
-
-bool Channel::_UpdateIntInDB(const std::string& colName, int colValue) const
-{
- // Prevent SQL-injection
- std::string _name(m_name);
- CharacterDatabase.escape_string(_name);
- CharacterDatabase.PExecute("UPDATE channels SET %s = '%u' WHERE m_name = '%s' AND m_team = '%u'",
- colName.c_str(), colValue, _name.c_str(), m_Team);
- return true;
-}
-
-void Channel::_UpdateBanListInDB() const
-{
- // save banlist
if (m_IsSaved)
{
std::ostringstream banlist;
BannedList::const_iterator iter;
for (iter = banned.begin(); iter != banned.end(); ++iter)
banlist << (*iter) << " ";
+
std::string banListStr = banlist.str();
- if (_UpdateStringInDB("BannedList", banListStr))
- sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str());
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_CHANNEL);
+ stmt->setBool(0, m_announce);
+ stmt->setBool(1, m_ownership);
+ stmt->setString(2, m_password);
+ stmt->setString(3, banListStr);
+ stmt->setString(4, m_name);
+ stmt->setUInt32(5, m_Team);
+ CharacterDatabase.Execute(stmt);
+
+ sLog.outDebug("Channel(%s) updated in database", m_name.c_str());
}
+
}
+void Channel::UpdateChannelUseageInDB() const
+{
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_CHANNEL_USAGE);
+ stmt->setString(0, m_name);
+ stmt->setUInt32(1, m_Team);
+ CharacterDatabase.Execute(stmt);
+}
+
+void Channel::CleanOldChannelsInDB()
+{
+ if (sWorld.getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION) > 0)
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_CHANNEL);
+ stmt->setUInt32(0, sWorld.getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION)*DAY);
+ CharacterDatabase.Execute(stmt);
+
+ sLog.outDebug("Cleaned out unused custom chat channels.");
+ }
+}
+
+
void Channel::Join(uint64 p, const char *pass)
{
WorldPacket data;
@@ -188,18 +202,20 @@ void Channel::Join(uint64 p, const char *pass)
JoinNotify(p);
- // if no owner first logged will become
- if (!IsConstant() && !m_ownerGUID)
+ // Custom channel handling
+ if (!IsConstant())
{
- SetOwner(p, (players.size() > 1 ? true : false));
- players[p].SetModerator(true);
+ // Update last_used timestamp in db
+ if(!players.empty())
+ UpdateChannelUseageInDB();
+
+ // If the channel has no owner yet and ownership is allowed, set the new owner.
+ if ( !m_ownerGUID && m_ownership)
+ {
+ SetOwner(p, (players.size() > 1 ? true : false));
+ players[p].SetModerator(true);
+ }
}
- /*
- else if (!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID()))
- {
- SetOwner(p, (players.size() > 1 ? true : false));
- players[p].SetModerator(true);
- }*/
}
void Channel::Leave(uint64 p, bool send)
@@ -239,11 +255,18 @@ void Channel::Leave(uint64 p, bool send)
LeaveNotify(p);
- if (changeowner)
+ if (!IsConstant())
{
- uint64 newowner = !players.empty() ? players.begin()->second.player : 0;
- players[newowner].SetModerator(true);
- SetOwner(newowner);
+ // Update last_used timestamp in db
+ UpdateChannelUseageInDB();
+
+ // If the channel owner left and there are still players inside, pick a new owner
+ if (changeowner && m_ownership && !players.empty())
+ {
+ uint64 newowner = players.begin()->second.player;
+ players[newowner].SetModerator(true);
+ SetOwner(newowner);
+ }
}
}
}
@@ -292,8 +315,8 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban)
{
banned.insert(bad->GetGUID());
MakePlayerBanned(&data, bad->GetGUID(), good);
- _UpdateBanListInDB();
+ UpdateChannelInDB();
}
else
MakePlayerKicked(&data, bad->GetGUID(), good);
@@ -302,9 +325,9 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban)
players.erase(bad->GetGUID());
bad->LeftChannel(this);
- if (changeowner)
+ if (changeowner && m_ownership && !players.empty())
{
- uint64 newowner = !players.empty() ? good : false;
+ uint64 newowner = good;
players[newowner].SetModerator(true);
SetOwner(newowner);
}
@@ -347,8 +370,8 @@ void Channel::UnBan(uint64 good, const char *badname)
WorldPacket data;
MakePlayerUnbanned(&data, bad->GetGUID(), good);
SendToAll(&data);
- //save banlist
- _UpdateBanListInDB();
+
+ UpdateChannelInDB();
}
}
}
@@ -363,12 +386,6 @@ void Channel::Password(uint64 p, const char *pass)
ChatHandler chat(plr);
- if (!m_public && sec <= SEC_MODERATOR)
- {
- chat.PSendSysMessage(LANG_CHANNEL_NOT_PUBLIC);
- return;
- }
-
if (!IsOn(p))
{
WorldPacket data;
@@ -388,8 +405,8 @@ void Channel::Password(uint64 p, const char *pass)
WorldPacket data;
MakePasswordChanged(&data, p);
SendToAll(&data);
- if (m_IsSaved && _UpdateStringInDB("m_password", m_password))
- sLog.outDebug("Channel(%s) password saved", m_name.c_str());
+
+ UpdateChannelInDB();
}
}
@@ -595,43 +612,8 @@ void Channel::Announce(uint64 p)
else
MakeAnnouncementsOff(&data, p);
SendToAll(&data);
- if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0))
- sLog.outDebug("Channel(%s) announce saved", m_name.c_str());
-
- }
-}
-
-void Channel::Moderate(uint64 p)
-{
- uint32 sec = 0;
- Player *plr = sObjectMgr.GetPlayer(p);
- if (plr)
- sec = plr->GetSession()->GetSecurity();
-
- if (!IsOn(p))
- {
- WorldPacket data;
- MakeNotMember(&data);
- SendToOne(&data, p);
- }
- else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER)
- {
- WorldPacket data;
- MakeNotModerator(&data);
- SendToOne(&data, p);
- }
- else
- {
- m_moderate = !m_moderate;
- WorldPacket data;
- if (m_moderate)
- MakeModerationOn(&data, p);
- else
- MakeModerationOff(&data, p);
- SendToAll(&data);
- if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0))
- sLog.outDebug("Channel(%s) announce saved", m_name.c_str());
+ UpdateChannelInDB();
}
}
@@ -659,7 +641,7 @@ void Channel::Say(uint64 p, const char *what, uint32 lang)
MakeMuted(&data);
SendToOne(&data, p);
}
- else if (m_moderate && !players[p].IsModerator() && sec < SEC_GAMEMASTER)
+ else if (!players[p].IsModerator() && sec < SEC_GAMEMASTER)
{
WorldPacket data;
MakeNotModerator(&data);
@@ -768,9 +750,8 @@ void Channel::SetOwner(uint64 guid, bool exclaim)
MakeOwnerChanged(&data, m_ownerGUID);
SendToAll(&data);
}
- if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0))
- sLog.outDebug("Channel(%s) moderate saved", m_name.c_str());
+ UpdateChannelInDB();
}
}
@@ -936,20 +917,6 @@ void Channel::MakeAnnouncementsOff(WorldPacket *data, uint64 guid)
*data << uint64(guid);
}
-// done 0x0F
-void Channel::MakeModerationOn(WorldPacket *data, uint64 guid)
-{
- MakeNotifyPacket(data, CHAT_MODERATION_ON_NOTICE);
- *data << uint64(guid);
-}
-
-// done 0x10
-void Channel::MakeModerationOff(WorldPacket *data, uint64 guid)
-{
- MakeNotifyPacket(data, CHAT_MODERATION_OFF_NOTICE);
- *data << uint64(guid);
-}
-
// done 0x11
void Channel::MakeMuted(WorldPacket *data)
{
diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h
index 02bbaa54f51..63f8fa6b502 100755
--- a/src/server/game/Chat/Channels/Channel.h
+++ b/src/server/game/Chat/Channels/Channel.h
@@ -48,8 +48,8 @@ enum ChatNotify
CHAT_MODE_CHANGE_NOTICE = 0x0C, //?
CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s.";
CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s.";
- CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
- CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
+ // CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s.";
+ // CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s.";
CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak.";
CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s.";
CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are banned from that channel.";
@@ -150,8 +150,7 @@ class Channel
typedef std::set<uint64> BannedList;
BannedList banned;
bool m_announce;
- bool m_moderate;
- bool m_public;
+ bool m_ownership;
std::string m_name;
std::string m_password;
uint8 m_flags;
@@ -178,8 +177,6 @@ class Channel
void MakeModeChange(WorldPacket *data, uint64 guid, uint8 oldflags); //+ 0x0C
void MakeAnnouncementsOn(WorldPacket *data, uint64 guid); //+ 0x0D
void MakeAnnouncementsOff(WorldPacket *data, uint64 guid); //+ 0x0E
- void MakeModerationOn(WorldPacket *data, uint64 guid); //+ 0x0F
- void MakeModerationOff(WorldPacket *data, uint64 guid); //+ 0x10
void MakeMuted(WorldPacket *data); //? 0x11
void MakePlayerKicked(WorldPacket *data, uint64 bad, uint64 good); //? 0x12
void MakeBanned(WorldPacket *data); //? 0x13
@@ -207,9 +204,8 @@ class Channel
bool IsOn(uint64 who) const { return players.find(who) != players.end(); }
bool IsBanned(uint64 guid) const { return banned.find(guid) != banned.end(); }
- bool _UpdateStringInDB(const std::string& colName, const std::string& colValue) const;
- bool _UpdateIntInDB(const std::string& colName, int colValue) const;
- void _UpdateBanListInDB() const;
+ void UpdateChannelInDB() const;
+ void UpdateChannelUseageInDB() const;
uint8 GetPlayerFlags(uint64 p) const
{
@@ -278,13 +274,14 @@ class Channel
void UnsetMute(uint64 p, const char *newname) { SetMode(p, newname, false, false); }
void List(Player* p);
void Announce(uint64 p);
- void Moderate(uint64 p);
void Say(uint64 p, const char *what, uint32 lang);
void Invite(uint64 p, const char *newp);
void Voice(uint64 guid1, uint64 guid2);
void DeVoice(uint64 guid1, uint64 guid2);
void JoinNotify(uint64 guid); // invisible notify
void LeaveNotify(uint64 guid); // invisible notify
+ void SetOwnership(bool ownership) { m_ownership = ownership; };
+ static void CleanOldChannelsInDB();
};
#endif
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index bc6d1f1dbdc..472ae27b735 100755
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -150,8 +150,8 @@ ChatCommand * ChatHandler::getCommandTable()
static ChatCommand channelSetCommandTable[] =
{
- { "public", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleChannelSetPublic>, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "ownership", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleChannelSetOwnership>, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
static ChatCommand channelCommandTable[] =
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index 452fa070b6b..cd9633c4d97 100755
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -166,7 +166,7 @@ class ChatHandler
bool HandleCharacterReputationCommand(const char* args);
bool HandleCharacterTitlesCommand(const char* args);
- bool HandleChannelSetPublic(const char *args);
+ bool HandleChannelSetOwnership(const char *args);
bool HandlePossessCommand(const char* args);
bool HandleUnPossessCommand(const char* args);
diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp
index efff0a0c88a..20b4ae7fc7a 100755
--- a/src/server/game/Chat/Commands/Level3.cpp
+++ b/src/server/game/Chat/Commands/Level3.cpp
@@ -61,6 +61,7 @@
#include "CreatureTextMgr.h"
#include "SmartAI.h"
#include "Group.h"
+#include "ChannelMgr.h"
bool ChatHandler::HandleMaxSkillCommand(const char* /*args*/)
{
@@ -4400,25 +4401,38 @@ bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)
return true;
}
-bool ChatHandler::HandleChannelSetPublic(const char *args)
+bool ChatHandler::HandleChannelSetOwnership(const char *args)
{
if (!*args)
return false;
- std::string channel = strtok((char*)args, " ");
- uint32 val = atoi((char*)args);
+ char *channel = strtok((char*)args, " ");
+ char *argstr = strtok(NULL, "");
- if (val)
+ if (!channel || !argstr)
+ return false;
+
+ Player *player = m_session->GetPlayer();
+ Channel *chn;
+
+ if (ChannelMgr* cMgr = channelMgr(player->GetTeam()))
+ chn = cMgr->GetChannel(channel, player);
+
+ if (strcmp(argstr, "on") == 0)
{
- CharacterDatabase.PExecute("UPDATE channels SET m_public = 1 WHERE m_name LIKE '%s'", channel.c_str());
- val = 1;
+ if(chn)
+ chn->SetOwnership(true);
+ CharacterDatabase.PExecute("UPDATE channels SET m_ownership = 1 WHERE m_name LIKE '%s'", channel);
+ PSendSysMessage(LANG_CHANNEL_ENABLE_OWNERSHIP, channel);
}
- else
+ else if (strcmp(argstr, "off") == 0)
{
- CharacterDatabase.PExecute("UPDATE channels SET m_public = 0 WHERE m_name LIKE '%s'", channel.c_str());
- val = 0;
+ if(chn)
+ chn->SetOwnership(false);
+ CharacterDatabase.PExecute("UPDATE channels SET m_ownership = 0 WHERE m_name LIKE '%s'", channel);
+ PSendSysMessage(LANG_CHANNEL_DISABLE_OWNERSHIP, channel);
}
-
- PSendSysMessage(LANG_CHANNEL_PUBLIC_CHANGED, channel.c_str(), val);
+ else
+ return false;
return true;
}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index b20b43d0f6c..628ea16c330 100755
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -906,8 +906,8 @@ enum TrinityStrings
LANG_MOUNTABLE = 5019,
LANG_NPCINFO_PHASEMASK = 5020,
LANG_NPCINFO_ARMOR = 5021,
- LANG_CHANNEL_NOT_PUBLIC = 5022,
- LANG_CHANNEL_PUBLIC_CHANGED = 5023,
+ LANG_CHANNEL_ENABLE_OWNERSHIP = 5022,
+ LANG_CHANNEL_DISABLE_OWNERSHIP = 5023,
LANG_GOINFO_ENTRY = 5024,
LANG_GOINFO_TYPE = 5025,
LANG_GOINFO_DISPLAYID = 5026,
diff --git a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp
index 2a56dc31e74..f14a8663c38 100755
--- a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp
@@ -281,17 +281,6 @@ void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket)
chn->Announce(_player->GetGUID());
}
-void WorldSession::HandleChannelModerate(WorldPacket& recvPacket)
-{
- sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
- //recvPacket.hexlike();
- std::string channelname;
- recvPacket >> channelname;
- if (ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
- if (Channel *chn = cMgr->GetChannel(channelname, _player))
- chn->Moderate(_player->GetGUID());
-}
-
void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket)
{
sLog.outDebug("Opcode %u", recvPacket.GetOpcode());
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index e784fe65aaf..457aeb195e9 100755
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -194,7 +194,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x0A5*/ { "CMSG_CHANNEL_BAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelBan },
/*0x0A6*/ { "CMSG_CHANNEL_UNBAN", STATUS_LOGGEDIN, &WorldSession::HandleChannelUnban },
/*0x0A7*/ { "CMSG_CHANNEL_ANNOUNCEMENTS", STATUS_LOGGEDIN, &WorldSession::HandleChannelAnnouncements },
- /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_LOGGEDIN, &WorldSession::HandleChannelModerate },
+ /*0x0A8*/ { "CMSG_CHANNEL_MODERATE", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x0A9*/ { "SMSG_UPDATE_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x0AA*/ { "SMSG_DESTROY_OBJECT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x0AB*/ { "CMSG_USE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleUseItemOpcode },
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 2670e63c230..3a73fa295f6 100755
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -71,6 +71,7 @@
#include "WeatherMgr.h"
#include "CreatureTextMgr.h"
#include "SmartAI.h"
+#include "Channel.h"
volatile bool World::m_stopEvent = false;
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
@@ -576,6 +577,8 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_AUCTION_LEVEL_REQ] = sConfig.GetIntDefault("LevelReq.Auction", 1);
m_int_configs[CONFIG_MAIL_LEVEL_REQ] = sConfig.GetIntDefault("LevelReq.Mail", 1);
m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = sConfig.GetBoolDefault("AllowPlayerCommands", 1);
+ m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = sConfig.GetBoolDefault("PreserveCustomChannels", false);
+ m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = sConfig.GetIntDefault("PreserveCustomChannelDuration", 14);
m_bool_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true);
m_int_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILLISECONDS);
m_int_configs[CONFIG_INTERVAL_DISCONNECT_TOLERANCE] = sConfig.GetIntDefault("DisconnectToleranceInterval", 0);
@@ -1673,6 +1676,9 @@ void World::SetInitialWorldSettings()
// Delete all characters which have been deleted X days before
Player::DeleteOldCharacters();
+ // Delete all custom channels which haven't been used for PreserveCustomChannelDuration days.
+ Channel::CleanOldChannelsInDB();
+
sLog.outString("Starting Arena Season...");
sGameEventMgr.StartArenaSeason();
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 998703dfb42..750c7dc7e4a 100755
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -163,6 +163,7 @@ enum WorldBoolConfigs
CONFIG_AUTOBROADCAST,
CONFIG_ALLOW_TICKETS,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
+ CONFIG_PRESERVE_CUSTOM_CHANNELS,
BOOL_CONFIG_VALUE_COUNT
};
@@ -308,6 +309,7 @@ enum WorldIntConfigs
CONFIG_AUTOBROADCAST_INTERVAL,
CONFIG_MAX_RESULTS_LOOKUP_COMMANDS,
CONFIG_DB_PING_INTERVAL,
+ CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION,
INT_CONFIG_VALUE_COUNT
};
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 92257ba9ace..1164fcceffe 100755
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -215,5 +215,12 @@ bool CharacterDatabaseConnection::Open()
PrepareStatement(CHAR_DEL_CRESPAWNTIME, "DELETE FROM creature_respawn WHERE guid = ? AND instance = ?");
PrepareStatement(CHAR_ADD_CRESPAWNTIME, "INSERT INTO creature_respawn VALUES (?, ?, ?)");
+ // Chat channel handling
+ PrepareStatement(CHAR_LOAD_CHANNEL, "SELECT m_announce, m_ownership, m_password, BannedList FROM channels WHERE m_name = ? AND m_team = ?");
+ PrepareStatement(CHAR_ADD_CHANNEL, "INSERT INTO channels (m_name, m_team, last_used) VALUES (? , ?, UNIX_TIMESTAMP())");
+ PrepareStatement(CHAR_SET_CHANNEL, "UPDATE channels SET m_announce = ?, m_ownership = ?, m_password = ?, BannedList = ?, last_used = UNIX_TIMESTAMP() WHERE m_name = ? AND m_team = ?");
+ PrepareStatement(CHAR_SET_CHANNEL_USAGE, "UPDATE channels SET last_used = UNIX_TIMESTAMP() WHERE m_name = ? AND m_team = ?");
+ PrepareStatement(CHAR_CLEAN_CHANNEL, "DELETE FROM channels WHERE m_ownership = 1 AND (last_used + ?) < UNIX_TIMESTAMP()");
+
return true;
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index e8fc1b64418..3346632e75d 100755
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -181,6 +181,12 @@ enum CharacterDatabaseStatements
CHAR_DEL_CRESPAWNTIME,
CHAR_ADD_CRESPAWNTIME,
+ CHAR_LOAD_CHANNEL,
+ CHAR_ADD_CHANNEL,
+ CHAR_SET_CHANNEL,
+ CHAR_SET_CHANNEL_USAGE,
+ CHAR_CLEAN_CHANNEL,
+
MAX_CHARACTERDATABASE_STATEMENTS,
};
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 0e5acea124f..a74fd7c0b71 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1371,9 +1371,10 @@ DungeonFinder.Enable = 0
#
# DBC.EnforceItemAttributes
-# Disallow overriding item attributes stored in DBC files with values from the database
-# Default: 0 - Off, Use DB values
-# 1 - On, Enforce DBC Values (default)
+# Description: Disallow overriding item attributes stored in DBC files with values from the
+# database.
+# Default: 1 - (Enabled, Enforce DBC values)
+# 0 - (Disabled, Use database values)
DBC.EnforceItemAttributes = 1
@@ -1745,6 +1746,27 @@ ChatLevelReq.Say = 1
AllowPlayerCommands = 1
#
+# PreserveCustomChannels
+# Description: Store custom chat channel settings like password, automatic ownership handout
+# or ban list in the database. Needs to be enabled to save custom
+# world/trade/etc. channels that have automatic ownership handout disabled.
+# (.channel set ownership $channel off)
+# Default: 0 - (Disabled, Blizzlike, Channel settings are lost if last person left)
+# 1 - (Enabled)
+
+PreserveCustomChannels = 1
+
+#
+# PreserveCustomChannelDuration
+# Description: Time (in days) that needs to pass before the customs chat channels get
+# cleaned up from the database. Only channels with ownership handout enabled
+# (default behavior) will be cleaned.
+# Default: 14 - (Enabled, Clean channels that haven't been used for 14 days)
+# 0 - (Disabled, Infinite channel storage)
+
+PreserveCustomChannelDuration = 14
+
+#
###################################################################################################
###################################################################################################