mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-17 19:05:42 +00:00
feat(Core/Chat): new argument parsing and unify chat hyperlink parsing (#6243)
This commit is contained in:
@@ -15,10 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Chat.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Chat.h"
|
||||
#include "ChatLink.h"
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
@@ -30,6 +29,7 @@
|
||||
#include "Realm.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Tokenize.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
@@ -39,45 +39,9 @@
|
||||
#include "LuaEngine.h"
|
||||
#endif
|
||||
|
||||
bool ChatHandler::load_command_table = true;
|
||||
|
||||
std::vector<ChatCommand> const& ChatHandler::getCommandTable()
|
||||
Player* ChatHandler::GetPlayer() const
|
||||
{
|
||||
static std::vector<ChatCommand> commandTableCache;
|
||||
|
||||
if (LoadCommandTable())
|
||||
{
|
||||
SetLoadCommandTable(false);
|
||||
|
||||
std::vector<ChatCommand> cmds = sScriptMgr->GetChatCommands();
|
||||
commandTableCache.swap(cmds);
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
std::string name = fields[0].GetString();
|
||||
|
||||
SetDataForCommandInTable(commandTableCache, name.c_str(), fields[1].GetUInt8(), fields[2].GetString(), name);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
return commandTableCache;
|
||||
}
|
||||
|
||||
std::string ChatHandler::PGetParseString(uint32 entry, ...) const
|
||||
{
|
||||
const char* format = GetAcoreString(entry);
|
||||
char str[1024];
|
||||
va_list ap;
|
||||
va_start(ap, entry);
|
||||
vsnprintf(str, 1024, format, ap);
|
||||
va_end(ap);
|
||||
return std::string(str);
|
||||
return m_session ? m_session->GetPlayer() : nullptr;
|
||||
}
|
||||
|
||||
char const* ChatHandler::GetAcoreString(uint32 entry) const
|
||||
@@ -85,10 +49,10 @@ char const* ChatHandler::GetAcoreString(uint32 entry) const
|
||||
return m_session->GetAcoreString(entry);
|
||||
}
|
||||
|
||||
bool ChatHandler::isAvailable(ChatCommand const& cmd) const
|
||||
bool ChatHandler::IsAvailable(uint32 securityLevel) const
|
||||
{
|
||||
// check security level only for simple command (without child commands)
|
||||
return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel);
|
||||
return m_session->GetSecurity() >= AccountTypes(securityLevel);
|
||||
}
|
||||
|
||||
bool ChatHandler::HasLowerSecurity(Player* target, ObjectGuid guid, bool strong)
|
||||
@@ -141,83 +105,50 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatHandler::hasStringAbbr(const char* name, const char* part)
|
||||
void ChatHandler::SendSysMessage(std::string_view str, bool escapeCharacters)
|
||||
{
|
||||
// non "" command
|
||||
if (*name)
|
||||
std::string msg{ str };
|
||||
|
||||
// Replace every "|" with "||" in msg
|
||||
if (escapeCharacters && msg.find('|') != std::string::npos)
|
||||
{
|
||||
// "" part from non-"" command
|
||||
if (!*part)
|
||||
return false;
|
||||
std::vector<std::string_view> tokens = Acore::Tokenize(msg, '|', true);
|
||||
std::ostringstream stream;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!*part)
|
||||
return true;
|
||||
else if (!*name)
|
||||
return false;
|
||||
else if (tolower(*name) != tolower(*part))
|
||||
return false;
|
||||
++name;
|
||||
++part;
|
||||
}
|
||||
for (size_t i = 0; i < tokens.size() - 1; ++i)
|
||||
stream << tokens[i] << "||";
|
||||
|
||||
stream << tokens[tokens.size() - 1];
|
||||
|
||||
msg = stream.str();
|
||||
}
|
||||
// allow with any for ""
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatHandler::SendSysMessage(const char* str)
|
||||
{
|
||||
WorldPacket data;
|
||||
|
||||
// need copy to prevent corruption by strtok call in LineFromMessage original string
|
||||
char* buf = strdup(str);
|
||||
char* pos = buf;
|
||||
|
||||
while (char* line = LineFromMessage(pos))
|
||||
for (std::string_view line : Acore::Tokenize(str, '\n', true))
|
||||
{
|
||||
BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line);
|
||||
m_session->SendPacket(&data);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void ChatHandler::SendGlobalSysMessage(const char* str)
|
||||
{
|
||||
// Chat output
|
||||
WorldPacket data;
|
||||
|
||||
// need copy to prevent corruption by strtok call in LineFromMessage original string
|
||||
char* buf = strdup(str);
|
||||
char* pos = buf;
|
||||
|
||||
while (char* line = LineFromMessage(pos))
|
||||
for (std::string_view line : Acore::Tokenize(str, '\n', true))
|
||||
{
|
||||
BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line);
|
||||
sWorld->SendGlobalMessage(&data);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void ChatHandler::SendGlobalGMSysMessage(const char* str)
|
||||
{
|
||||
// Chat output
|
||||
WorldPacket data;
|
||||
|
||||
// need copy to prevent corruption by strtok call in LineFromMessage original string
|
||||
char* buf = strdup(str);
|
||||
char* pos = buf;
|
||||
|
||||
while (char* line = LineFromMessage(pos))
|
||||
for (std::string_view line : Acore::Tokenize(str, '\n', true))
|
||||
{
|
||||
BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line);
|
||||
sWorld->SendGlobalGMMessage(&data);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void ChatHandler::SendSysMessage(uint32 entry)
|
||||
@@ -225,388 +156,42 @@ void ChatHandler::SendSysMessage(uint32 entry)
|
||||
SendSysMessage(GetAcoreString(entry));
|
||||
}
|
||||
|
||||
void ChatHandler::PSendSysMessage(uint32 entry, ...)
|
||||
bool ChatHandler::_ParseCommands(std::string_view text)
|
||||
{
|
||||
const char* format = GetAcoreString(entry);
|
||||
va_list ap;
|
||||
char str [2048];
|
||||
va_start(ap, entry);
|
||||
vsnprintf(str, 2048, format, ap);
|
||||
va_end(ap);
|
||||
SendSysMessage(str);
|
||||
}
|
||||
|
||||
void ChatHandler::PSendSysMessage(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char str [2048];
|
||||
va_start(ap, format);
|
||||
vsnprintf(str, 2048, format, ap);
|
||||
va_end(ap);
|
||||
SendSysMessage(str);
|
||||
}
|
||||
|
||||
bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, const char* text, std::string const& fullcmd)
|
||||
{
|
||||
char const* oldtext = text;
|
||||
std::string cmd = "";
|
||||
|
||||
while (*text != ' ' && *text != '\0')
|
||||
{
|
||||
cmd += *text;
|
||||
++text;
|
||||
}
|
||||
|
||||
while (*text == ' ') ++text;
|
||||
|
||||
for (uint32 i = 0; i < table.size(); ++i)
|
||||
{
|
||||
if (!hasStringAbbr(table[i].Name, cmd.c_str()))
|
||||
continue;
|
||||
|
||||
bool match = false;
|
||||
if (strlen(table[i].Name) > cmd.length())
|
||||
{
|
||||
for (uint32 j = 0; j < table.size(); ++j)
|
||||
{
|
||||
if (!hasStringAbbr(table[j].Name, cmd.c_str()))
|
||||
continue;
|
||||
|
||||
if (strcmp(table[j].Name, cmd.c_str()) == 0)
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
continue;
|
||||
|
||||
// select subcommand from child commands list
|
||||
if (!table[i].ChildCommands.empty())
|
||||
{
|
||||
if (!ExecuteCommandInTable(table[i].ChildCommands, text, fullcmd.c_str()))
|
||||
{
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnCommand(GetSession() ? GetSession()->GetPlayer() : nullptr, oldtext))
|
||||
return true;
|
||||
#endif
|
||||
if (text[0] != '\0')
|
||||
SendSysMessage(LANG_NO_SUBCMD);
|
||||
else
|
||||
SendSysMessage(LANG_CMD_SYNTAX);
|
||||
|
||||
ShowHelpForCommand(table[i].ChildCommands, text);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// must be available and have handler
|
||||
if (!table[i].Handler || !isAvailable(table[i]))
|
||||
continue;
|
||||
|
||||
SetSentErrorMessage(false);
|
||||
// table[i].Name == "" is special case: send original command to handler
|
||||
if ((table[i].Handler)(this, table[i].Name[0] != '\0' ? text : oldtext))
|
||||
{
|
||||
if (!m_session) // ignore console
|
||||
return true;
|
||||
|
||||
Player* player = m_session->GetPlayer();
|
||||
if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()))
|
||||
{
|
||||
ObjectGuid guid = player->GetTarget();
|
||||
uint32 areaId = player->GetAreaId();
|
||||
uint32 zoneId = player->GetZoneId();
|
||||
std::string areaName = "Unknown";
|
||||
std::string zoneName = "Unknown";
|
||||
int locale = GetSessionDbcLocale();
|
||||
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||
{
|
||||
areaName = area->area_name[locale];
|
||||
}
|
||||
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(zoneId))
|
||||
{
|
||||
zoneName = zone->area_name[locale];
|
||||
}
|
||||
|
||||
LOG_GM(m_session->GetAccountId(), "Command: %s [Player: %s (%s) (Account: %u) X: %f Y: %f Z: %f Map: %u (%s) Area: %u (%s) Zone: %u (%s) Selected: %s (%s)]",
|
||||
fullcmd.c_str(), player->GetName().c_str(), player->GetGUID().ToString().c_str(),
|
||||
m_session->GetAccountId(), player->GetPositionX(), player->GetPositionY(),
|
||||
player->GetPositionZ(), player->GetMapId(),
|
||||
player->GetMap()->GetMapName(),
|
||||
areaId, areaName.c_str(), zoneId, zoneName.c_str(),
|
||||
(player->GetSelectedUnit()) ? player->GetSelectedUnit()->GetName().c_str() : "",
|
||||
guid.ToString().c_str());
|
||||
}
|
||||
}
|
||||
// some commands have custom error messages. Don't send the default one in these cases.
|
||||
else if (!HasSentErrorMessage())
|
||||
{
|
||||
if (!table[i].Help.empty())
|
||||
SendSysMessage(table[i].Help.c_str());
|
||||
else
|
||||
SendSysMessage(LANG_CMD_SYNTAX);
|
||||
}
|
||||
|
||||
if (Acore::ChatCommands::TryExecuteCommand(*this, text))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatHandler::SetDataForCommandInTable(std::vector<ChatCommand>& table, char const* text, uint32 security, std::string const& help, std::string const& fullcommand)
|
||||
{
|
||||
std::string cmd = "";
|
||||
|
||||
while (*text != ' ' && *text != '\0')
|
||||
{
|
||||
cmd += *text;
|
||||
++text;
|
||||
}
|
||||
|
||||
while (*text == ' ') ++text;
|
||||
|
||||
for (uint32 i = 0; i < table.size(); i++)
|
||||
{
|
||||
// for data fill use full explicit command names
|
||||
if (table[i].Name != cmd)
|
||||
continue;
|
||||
|
||||
// select subcommand from child commands list (including "")
|
||||
if (!table[i].ChildCommands.empty())
|
||||
{
|
||||
if (SetDataForCommandInTable(table[i].ChildCommands, text, security, help, fullcommand))
|
||||
return true;
|
||||
else if (*text)
|
||||
return false;
|
||||
|
||||
// fail with "" subcommands, then use normal level up command instead
|
||||
}
|
||||
// expected subcommand by full name DB content
|
||||
else if (*text)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `command` have unexpected subcommand '%s' in command '%s', skip.", text, fullcommand.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
table[i].SecurityLevel = security;
|
||||
table[i].Help = help;
|
||||
return true;
|
||||
}
|
||||
|
||||
// in case "" command let process by caller
|
||||
if (!cmd.empty())
|
||||
{
|
||||
if (&table == &getCommandTable())
|
||||
LOG_ERROR("sql.sql", "Table `command` have non-existing command '%s', skip.", cmd.c_str());
|
||||
else
|
||||
LOG_ERROR("sql.sql", "Table `command` have non-existing subcommand '%s' in command '%s', skip.", cmd.c_str(), fullcommand.c_str());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatHandler::ParseCommands(char const* text)
|
||||
{
|
||||
ASSERT(text);
|
||||
ASSERT(*text);
|
||||
|
||||
std::string fullcmd = text;
|
||||
|
||||
// Pretend commands don't exist for regular players
|
||||
if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS))
|
||||
return false;
|
||||
|
||||
/// chat case (.command or !command format)
|
||||
if (m_session)
|
||||
{
|
||||
if (text[0] != '!' && text[0] != '.')
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ignore single . and ! in line
|
||||
if (strlen(text) < 2)
|
||||
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] == '!'))
|
||||
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))
|
||||
{
|
||||
#ifdef ELUNA
|
||||
if (!sEluna->OnCommand(GetSession() ? GetSession()->GetPlayer() : nullptr, text))
|
||||
return true;
|
||||
#endif
|
||||
if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()))
|
||||
return false;
|
||||
|
||||
SendSysMessage(LANG_NO_CMD);
|
||||
}
|
||||
// Send error message for GMs
|
||||
PSendSysMessage(LANG_CMD_INVALID, STRING_VIEW_FMT_ARG(text));
|
||||
SetSentErrorMessage(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::isValidChatMessage(char const* message)
|
||||
bool ChatHandler::ParseCommands(std::string_view text)
|
||||
{
|
||||
/*
|
||||
Valid examples:
|
||||
|cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
|
||||
|cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
|
||||
|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
|
||||
|cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
|
||||
|cff71d5ff|Hspell:21563|h[Command]|h|r
|
||||
|cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
|
||||
|cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
|
||||
|cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
|
||||
ASSERT(!text.empty());
|
||||
|
||||
| will be escaped to ||
|
||||
*/
|
||||
|
||||
if (strlen(message) > 255)
|
||||
// chat case (.command or !command format)
|
||||
if ((text[0] != '!') && (text[0] != '.'))
|
||||
return false;
|
||||
|
||||
// more simple checks
|
||||
if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3)
|
||||
{
|
||||
const char validSequence[6] = "cHhhr";
|
||||
const char* validSequenceIterator = validSequence;
|
||||
const std::string validCommands = "cHhr|";
|
||||
|
||||
while (*message)
|
||||
{
|
||||
// find next pipe command
|
||||
message = strchr(message, '|');
|
||||
|
||||
if (!message)
|
||||
return true;
|
||||
|
||||
++message;
|
||||
char commandChar = *message;
|
||||
if (validCommands.find(commandChar) == std::string::npos)
|
||||
return false;
|
||||
|
||||
++message;
|
||||
// validate sequence
|
||||
if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2)
|
||||
{
|
||||
if (commandChar == *validSequenceIterator)
|
||||
{
|
||||
if (validSequenceIterator == validSequence + 4)
|
||||
validSequenceIterator = validSequence;
|
||||
else
|
||||
++validSequenceIterator;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return LinkExtractor(message).IsValidMessage();
|
||||
}
|
||||
|
||||
bool ChatHandler::ShowHelpForSubCommands(std::vector<ChatCommand> const& table, char const* cmd, char const* subcmd)
|
||||
{
|
||||
std::string list;
|
||||
for (uint32 i = 0; i < table.size(); ++i)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!isAvailable(table[i]))
|
||||
continue;
|
||||
|
||||
// for empty subcmd show all available
|
||||
if (*subcmd && !hasStringAbbr(table[i].Name, subcmd))
|
||||
continue;
|
||||
|
||||
if (m_session)
|
||||
list += "\n |- ";
|
||||
else
|
||||
list += "\n\r |- ";
|
||||
|
||||
list += table[i].Name;
|
||||
|
||||
if (!table[i].ChildCommands.empty())
|
||||
list += " ...";
|
||||
}
|
||||
|
||||
if (list.empty())
|
||||
// ignore single . and ! in line
|
||||
if (text.length() < 2)
|
||||
return false;
|
||||
|
||||
if (&table == &getCommandTable())
|
||||
{
|
||||
SendSysMessage(LANG_AVIABLE_CMD);
|
||||
PSendSysMessage("%s", list.c_str());
|
||||
}
|
||||
else
|
||||
PSendSysMessage(LANG_SUBCMDS_LIST, cmd, list.c_str());
|
||||
// ignore messages staring from many dots.
|
||||
if (text[1] == text[0])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
// ignore messages with separator after .
|
||||
if (text[1] == Acore::Impl::ChatCommands::COMMAND_DELIMITER)
|
||||
return false;
|
||||
|
||||
bool ChatHandler::ShowHelpForCommand(std::vector<ChatCommand> const& table, const char* cmd)
|
||||
{
|
||||
if (*cmd)
|
||||
{
|
||||
for (uint32 i = 0; i < table.size(); ++i)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!isAvailable(table[i]))
|
||||
continue;
|
||||
|
||||
if (!hasStringAbbr(table[i].Name, cmd))
|
||||
continue;
|
||||
|
||||
// have subcommand
|
||||
char const* subcmd = (*cmd) ? strtok(nullptr, " ") : "";
|
||||
|
||||
if (!table[i].ChildCommands.empty() && subcmd && *subcmd)
|
||||
{
|
||||
if (ShowHelpForCommand(table[i].ChildCommands, subcmd))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!table[i].Help.empty())
|
||||
SendSysMessage(table[i].Help.c_str());
|
||||
|
||||
if (!table[i].ChildCommands.empty())
|
||||
if (ShowHelpForSubCommands(table[i].ChildCommands, table[i].Name, subcmd ? subcmd : ""))
|
||||
return true;
|
||||
|
||||
return !table[i].Help.empty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32 i = 0; i < table.size(); ++i)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!isAvailable(table[i]))
|
||||
continue;
|
||||
|
||||
if (strlen(table[i].Name))
|
||||
continue;
|
||||
|
||||
if (!table[i].Help.empty())
|
||||
SendSysMessage(table[i].Help.c_str());
|
||||
|
||||
if (!table[i].ChildCommands.empty())
|
||||
if (ShowHelpForSubCommands(table[i].ChildCommands, "", ""))
|
||||
return true;
|
||||
|
||||
return !table[i].Help.empty();
|
||||
}
|
||||
}
|
||||
|
||||
return ShowHelpForSubCommands(table, "", cmd);
|
||||
return _ParseCommands(text.substr(1));
|
||||
}
|
||||
|
||||
size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag,
|
||||
@@ -1009,21 +594,6 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
|
||||
return 0;
|
||||
}
|
||||
|
||||
GameTele const* ChatHandler::extractGameTeleFromLink(char* text)
|
||||
{
|
||||
// id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r
|
||||
char* cId = extractKeyFromLink(text, "Htele");
|
||||
if (!cId)
|
||||
return nullptr;
|
||||
|
||||
// id case (explicit or from shift link)
|
||||
if (cId[0] >= '0' || cId[0] <= '9')
|
||||
if (uint32 id = atoi(cId))
|
||||
return sObjectMgr->GetGameTele(id);
|
||||
|
||||
return sObjectMgr->GetGameTele(cId);
|
||||
}
|
||||
|
||||
enum GuidLinkType
|
||||
{
|
||||
SPELL_LINK_PLAYER = 0, // must be first for selection in not link case
|
||||
@@ -1140,10 +710,15 @@ bool ChatHandler::extractPlayerTarget(char* args, Player** player, ObjectGuid* p
|
||||
}
|
||||
else
|
||||
{
|
||||
// populate strtok buffer to prevent crashes
|
||||
static char dummy[1] = "";
|
||||
strtok(dummy, "");
|
||||
|
||||
Player* pl = getSelectedPlayer();
|
||||
// if allowed player pointer
|
||||
if (player)
|
||||
*player = pl;
|
||||
|
||||
// if allowed player guid (if no then only online players allowed)
|
||||
if (player_guid)
|
||||
*player_guid = pl ? pl->GetGUID() : ObjectGuid::Empty;
|
||||
@@ -1163,24 +738,6 @@ bool ChatHandler::extractPlayerTarget(char* args, Player** player, ObjectGuid* p
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatHandler::extractOptFirstArg(char* args, char** arg1, char** arg2)
|
||||
{
|
||||
char* p1 = strtok(args, " ");
|
||||
char* p2 = strtok(nullptr, " ");
|
||||
|
||||
if (!p2)
|
||||
{
|
||||
p2 = p1;
|
||||
p1 = nullptr;
|
||||
}
|
||||
|
||||
if (arg1)
|
||||
*arg1 = p1;
|
||||
|
||||
if (arg2)
|
||||
*arg2 = p2;
|
||||
}
|
||||
|
||||
char* ChatHandler::extractQuotedArg(char* args)
|
||||
{
|
||||
if (!*args)
|
||||
@@ -1247,18 +804,24 @@ char const* CliHandler::GetAcoreString(uint32 entry) const
|
||||
return sObjectMgr->GetAcoreStringForDBCLocale(entry);
|
||||
}
|
||||
|
||||
bool CliHandler::isAvailable(ChatCommand const& cmd) const
|
||||
{
|
||||
// skip non-console commands in console case
|
||||
return cmd.AllowConsole;
|
||||
}
|
||||
|
||||
void CliHandler::SendSysMessage(const char* str)
|
||||
void CliHandler::SendSysMessage(std::string_view str, bool /*escapeCharacters*/)
|
||||
{
|
||||
m_print(m_callbackArg, str);
|
||||
m_print(m_callbackArg, "\r\n");
|
||||
}
|
||||
|
||||
bool CliHandler::ParseCommands(std::string_view str)
|
||||
{
|
||||
if (str.empty())
|
||||
return false;
|
||||
|
||||
// Console allows using commands both with and without leading indicator
|
||||
if (str[0] == '.' || str[0] == '!')
|
||||
str = str.substr(1);
|
||||
|
||||
return _ParseCommands(str);
|
||||
}
|
||||
|
||||
std::string CliHandler::GetNameLink() const
|
||||
{
|
||||
return GetAcoreString(LANG_CONSOLE_COMMAND);
|
||||
|
||||
Reference in New Issue
Block a user