aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2017-07-28 02:45:57 +0200
committerShauren <shauren.trinity@gmail.com>2020-08-20 00:49:52 +0200
commit42c65c3bc22f97a96d9db481997d74e7103f8e64 (patch)
tree40f41e4066f28a454ba7eca6ca402e31cb43d560 /src
parente69b5d8fcc44728abd189e4832a383543218e5c1 (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.cpp153
-rw-r--r--src/server/game/Chat/Chat.h27
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp3
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: