diff options
author | Treeston <treeston.mmoc@gmail.com> | 2017-07-28 02:45:57 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2020-08-20 00:49:52 +0200 |
commit | 42c65c3bc22f97a96d9db481997d74e7103f8e64 (patch) | |
tree | 40f41e4066f28a454ba7eca6ca402e31cb43d560 /src | |
parent | e69b5d8fcc44728abd189e4832a383543218e5c1 (diff) |
Core/Chat: Provide a fully-formed protocol for addons to interact with GM commands (#20074)
Send success/fail state, allow interleaving, and indicate end of output. Add framework for supporting non-human-readable output in commands.
(cherry picked from commit 508c9d2fc1b20dc2cb40df533e823e1dfe2becc3)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Chat/Chat.cpp | 153 | ||||
-rw-r--r-- | src/server/game/Chat/Chat.h | 27 | ||||
-rw-r--r-- | src/server/game/Handlers/ChatHandler.cpp | 3 |
3 files changed, 160 insertions, 23 deletions
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index b50e7703f91..4cc184ae55f 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -36,6 +36,7 @@ #include "ScriptMgr.h" #include "World.h" #include "WorldSession.h" +#include <boost/algorithm/string/replace.hpp> ChatCommand::ChatCommand(char const* name, uint32 permission, bool allowConsole, pHandler handler, std::string help, std::vector<ChatCommand> childCommands /*= std::vector<ChatCommand>()*/) : Name(ASSERT_NOTNULL(name)), Permission(permission), AllowConsole(allowConsole), Handler(handler), Help(std::move(help)), ChildCommands(std::move(childCommands)) @@ -350,6 +351,7 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c SendSysMessage(table[i].Help.c_str()); else SendSysMessage(LANG_CMD_SYNTAX); + SetSentErrorMessage(true); } return true; @@ -413,41 +415,39 @@ bool ChatHandler::SetDataForCommandInTable(std::vector<ChatCommand>& table, char return false; } +bool ChatHandler::_ParseCommands(char const* text) +{ + if (ExecuteCommandInTable(getCommandTable(), text, text)) + return true; + + // Pretend commands don't exist for regular players + if (m_session && !m_session->HasPermission(rbac::RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR)) + return false; + + // Send error message for GMs + SendSysMessage(LANG_NO_CMD); + SetSentErrorMessage(true); + return true; +} + bool ChatHandler::ParseCommands(char const* text) { ASSERT(text); ASSERT(*text); - std::string fullcmd = text; - /// chat case (.command or !command format) - if (m_session) - { - if (text[0] != '!' && text[0] != '.') - return false; - } + if (text[0] != '!' && text[0] != '.') + return false; /// ignore single . and ! in line - if (strlen(text) < 2) + if (!text[1]) return false; - // original `text` can't be used. It content destroyed in command code processing. /// ignore messages staring from many dots. - if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!')) + if (text[1] == '!' || text[1] == '.') return false; - /// skip first . or ! (in console allowed use command with . and ! and without its) - if (text[0] == '!' || text[0] == '.') - ++text; - - if (!ExecuteCommandInTable(getCommandTable(), text, fullcmd)) - { - if (m_session && !m_session->HasPermission(rbac::RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR)) - return false; - - SendSysMessage(LANG_NO_CMD); - } - return true; + return _ParseCommands(text+1); } bool ChatHandler::isValidChatMessage(char const* message) @@ -1124,6 +1124,16 @@ void CliHandler::SendSysMessage(const char *str, bool /*escapeCharacters*/) m_print(m_callbackArg, "\r\n"); } +bool CliHandler::ParseCommands(char const* str) +{ + if (!str[0]) + return false; + // Console allows using commands both with and without leading indicator + if (str[0] == '.' || str[0] == '!') + ++str; + return _ParseCommands(str); +} + std::string CliHandler::GetNameLink() const { return GetTrinityString(LANG_CONSOLE_COMMAND); @@ -1187,3 +1197,102 @@ LocaleConstant CliHandler::GetSessionDbLocaleIndex() const { return sObjectMgr->GetDBCLocaleIndex(); } + +std::string const AddonChannelCommandHandler::PREFIX = "TrinityCore"; + +bool AddonChannelCommandHandler::ParseCommands(char const* str) +{ + char opcode = str[0]; + if (!opcode) // str[0] is opcode + return false; + if (!str[1] || !str[2] || !str[3] || !str[4]) // str[1] through str[4] is 4-character command counter + return false; + echo = str+1; + + switch (opcode) + { + case 'p': // p Ping + SendAck(); + return true; + case 'h': // h Issue human-readable command + case 'i': // i Issue command + if (!str[5]) + return false; + humanReadable = (opcode == 'h'); + if (_ParseCommands(str + 5)) // actual command starts at str[5] + { + if (!hadAck) + SendAck(); + if (HasSentErrorMessage()) + SendFailed(); + else + SendOK(); + } + else + { + SendSysMessage(LANG_NO_CMD); + SendFailed(); + } + return true; + default: + return false; + } +} + +void AddonChannelCommandHandler::Send(std::string const& msg) +{ + WorldPackets::Chat::Chat chat; + chat.Initialize(CHAT_MSG_WHISPER, LANG_ADDON, GetSession()->GetPlayer(), GetSession()->GetPlayer(), msg, 0, "", LOCALE_enUS, PREFIX); + GetSession()->SendPacket(chat.Write()); +} + +void AddonChannelCommandHandler::SendAck() // a Command acknowledged, no body +{ + ASSERT(echo); + char ack[6] = "a"; + memcpy(ack + 1, echo, 4); + ack[5] = '\0'; + Send(ack); + hadAck = true; +} + +void AddonChannelCommandHandler::SendOK() // o Command OK, no body +{ + ASSERT(echo); + char ok[6] = "o"; + memcpy(ok + 1, echo, 4); + ok[5] = '\0'; + Send(ok); +} + +void AddonChannelCommandHandler::SendFailed() // f Command failed, no body +{ + ASSERT(echo); + char fail[6] = "f"; + memcpy(fail + 1, echo, 4); + fail[5] = '\0'; + Send(fail); +} + +// m Command message, message in body +void AddonChannelCommandHandler::SendSysMessage(char const* str, bool escapeCharacters) +{ + ASSERT(echo); + if (!hadAck) + SendAck(); + + std::string msg = "m"; + msg.append(echo, 4); + std::string body(str); + if (escapeCharacters) + boost::replace_all(body, "|", "||"); + size_t pos, lastpos; + for (lastpos = 0, pos = body.find('\n', lastpos); pos != std::string::npos; lastpos = pos + 1, pos = body.find('\n', lastpos)) + { + std::string line(msg); + line.append(body, lastpos, pos - lastpos); + Send(line); + } + msg.append(body, lastpos, pos - lastpos); + Send(msg); +} diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index d9235d11227..c9624ed0703 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -84,7 +84,8 @@ class TC_GAME_API ChatHandler return Trinity::StringFormat(GetTrinityString(entry), std::forward<Args>(args)...); } - bool ParseCommands(const char* text); + bool _ParseCommands(char const* text); + virtual bool ParseCommands(char const* text); static std::vector<ChatCommand> const& getCommandTable(); static void invalidateCommandTable(); @@ -96,6 +97,7 @@ class TC_GAME_API ChatHandler // function with different implementation for chat/console virtual bool isAvailable(ChatCommand const& cmd) const; + virtual bool IsHumanReadable() const { return true; } virtual bool HasPermission(uint32 permission) const; virtual std::string GetNameLink() const; virtual bool needReportToTarget(Player* chr) const; @@ -162,6 +164,7 @@ class TC_GAME_API CliHandler : public ChatHandler bool isAvailable(ChatCommand const& cmd) const override; bool HasPermission(uint32 /*permission*/) const override { return true; } void SendSysMessage(const char *str, bool escapeCharacters) override; + bool ParseCommands(char const* str) override; std::string GetNameLink() const override; bool needReportToTarget(Player* chr) const override; LocaleConstant GetSessionDbcLocale() const override; @@ -172,4 +175,26 @@ class TC_GAME_API CliHandler : public ChatHandler Print* m_print; }; +class TC_GAME_API AddonChannelCommandHandler : public ChatHandler +{ + public: + static std::string const PREFIX; + + using ChatHandler::ChatHandler; + bool ParseCommands(char const* str) override; + void SendSysMessage(char const* str, bool escapeCharacters) override; + using ChatHandler::SendSysMessage; + bool IsHumanReadable() const override { return humanReadable; } + + private: + void Send(std::string const& msg); + void SendAck(); + void SendOK(); + void SendFailed(); + + char const* echo = nullptr; + bool hadAck = false; + bool humanReadable = false; +}; + #endif diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 031d8c1909c..1148823e2b9 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -432,6 +432,9 @@ void WorldSession::HandleChatAddonMessage(ChatMsg type, std::string prefix, std: if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) return; + if (prefix == AddonChannelCommandHandler::PREFIX && AddonChannelCommandHandler(this).ParseCommands(text.c_str())) + return; + switch (type) { case CHAT_MSG_GUILD: |