diff options
| -rw-r--r-- | patch | 704 | ||||
| -rw-r--r-- | sql/base/characters_database.sql | 12 | ||||
| -rw-r--r-- | sql/base/world_database.sql | 5 | ||||
| -rw-r--r-- | sql/updates/10548_characters_channel.sql | 8 | ||||
| -rw-r--r-- | sql/updates/10548_world_command.sql | 5 | ||||
| -rw-r--r-- | sql/updates/10548_world_trinity_string.sql | 4 | ||||
| -rwxr-xr-x | src/server/game/Chat/Channels/Channel.cpp | 243 | ||||
| -rwxr-xr-x | src/server/game/Chat/Channels/Channel.h | 17 | ||||
| -rwxr-xr-x | src/server/game/Chat/Chat.cpp | 4 | ||||
| -rwxr-xr-x | src/server/game/Chat/Chat.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Chat/Commands/Level3.cpp | 36 | ||||
| -rwxr-xr-x | src/server/game/Miscellaneous/Language.h | 4 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp | 11 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
| -rwxr-xr-x | src/server/game/World/World.cpp | 6 | ||||
| -rwxr-xr-x | src/server/game/World/World.h | 2 | ||||
| -rwxr-xr-x | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 7 | ||||
| -rwxr-xr-x | src/server/shared/Database/Implementation/CharacterDatabase.h | 6 | ||||
| -rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 28 |
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 + +# ################################################################################################### ################################################################################################### |
