mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 16:37:01 +00:00
[10242] Rewrite internal work chat command system.
* Use single command search function with recursion and reuse it in now more simple and consistent for execute/help/loading * Add intergiry checks for hardcoded part of commands list. Fix some cases base at it. * Fixed diff small problems in past code: - in console single symbol commands rejected (without dot start) - .help not output propertly subcommands list for not found subcommand - some other...
This commit is contained in:
parent
30a0701ca9
commit
a121f7a3e5
5 changed files with 379 additions and 229 deletions
|
|
@ -74,7 +74,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||||
|
|
||||||
static ChatCommand accountCommandTable[] =
|
static ChatCommand accountCommandTable[] =
|
||||||
{
|
{
|
||||||
{ "characters", SEC_CONSOLE, true, &ChatHandler::HandleAccountCharactersCommand, "", NULL },
|
{ "characters", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountCharactersCommand, "", NULL },
|
||||||
{ "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL },
|
{ "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL },
|
||||||
{ "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL },
|
{ "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL },
|
||||||
{ "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL },
|
{ "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL },
|
||||||
|
|
@ -624,22 +624,22 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||||
{ "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable},
|
{ "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable},
|
||||||
{ "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable },
|
{ "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable },
|
||||||
{ "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
|
{ "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
|
||||||
{ "gm", SEC_MODERATOR, true, NULL, "", gmCommandTable },
|
{ "gm", SEC_PLAYER, true, NULL, "", gmCommandTable },
|
||||||
{ "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
|
{ "honor", SEC_GAMEMASTER, false, NULL, "", honorCommandTable },
|
||||||
{ "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
|
{ "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
|
||||||
{ "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
|
{ "gobject", SEC_GAMEMASTER, false, NULL, "", gobjectCommandTable },
|
||||||
{ "guild", SEC_ADMINISTRATOR, true, NULL, "", guildCommandTable },
|
{ "guild", SEC_GAMEMASTER, true, NULL, "", guildCommandTable },
|
||||||
{ "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable },
|
{ "instance", SEC_ADMINISTRATOR, true, NULL, "", instanceCommandTable },
|
||||||
{ "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
|
{ "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
|
||||||
{ "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
|
{ "list", SEC_ADMINISTRATOR, true, NULL, "", listCommandTable },
|
||||||
{ "lookup", SEC_ADMINISTRATOR, true, NULL, "", lookupCommandTable },
|
{ "lookup", SEC_MODERATOR, true, NULL, "", lookupCommandTable },
|
||||||
{ "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
|
{ "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
|
||||||
{ "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
|
{ "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
|
||||||
{ "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
|
{ "pdump", SEC_ADMINISTRATOR, true, NULL, "", pdumpCommandTable },
|
||||||
{ "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
|
{ "quest", SEC_ADMINISTRATOR, false, NULL, "", questCommandTable },
|
||||||
{ "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
|
{ "reload", SEC_ADMINISTRATOR, true, NULL, "", reloadCommandTable },
|
||||||
{ "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable },
|
{ "reset", SEC_ADMINISTRATOR, true, NULL, "", resetCommandTable },
|
||||||
{ "server", SEC_ADMINISTRATOR, true, NULL, "", serverCommandTable },
|
{ "server", SEC_PLAYER, true, NULL, "", serverCommandTable },
|
||||||
{ "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
|
{ "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
|
||||||
{ "titles", SEC_GAMEMASTER, false, NULL, "", titlesCommandTable },
|
{ "titles", SEC_GAMEMASTER, false, NULL, "", titlesCommandTable },
|
||||||
{ "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
|
{ "wp", SEC_GAMEMASTER, false, NULL, "", wpCommandTable },
|
||||||
|
|
@ -711,6 +711,9 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||||
{
|
{
|
||||||
load_command_table = false;
|
load_command_table = false;
|
||||||
|
|
||||||
|
// check hardcoded part integrity
|
||||||
|
CheckIntergrity(commandTable, NULL);
|
||||||
|
|
||||||
QueryResult *result = WorldDatabase.Query("SELECT name,security,help FROM command");
|
QueryResult *result = WorldDatabase.Query("SELECT name,security,help FROM command");
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
|
@ -719,7 +722,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||||
Field *fields = result->Fetch();
|
Field *fields = result->Fetch();
|
||||||
std::string name = fields[0].GetCppString();
|
std::string name = fields[0].GetCppString();
|
||||||
|
|
||||||
SetDataForCommandInTable(commandTable, name.c_str(), fields[1].GetUInt16(), fields[2].GetCppString(), name);
|
SetDataForCommandInTable(commandTable, name.c_str(), fields[1].GetUInt16(), fields[2].GetCppString());
|
||||||
|
|
||||||
} while(result->NextRow());
|
} while(result->NextRow());
|
||||||
delete result;
|
delete result;
|
||||||
|
|
@ -881,11 +884,78 @@ void ChatHandler::PSendSysMessage(const char *format, ...)
|
||||||
SendSysMessage(str);
|
SendSysMessage(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcmd)
|
void ChatHandler::CheckIntergrity( ChatCommand *table, ChatCommand *parentCommand )
|
||||||
|
{
|
||||||
|
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
||||||
|
{
|
||||||
|
ChatCommand* command = &table[i];
|
||||||
|
|
||||||
|
if (parentCommand && command->SecurityLevel < parentCommand->SecurityLevel)
|
||||||
|
sLog.outError("Subcommand '%s' of command '%s' have less access level (%u) that parent (%u)",
|
||||||
|
command->Name, parentCommand->Name, command->SecurityLevel, parentCommand->SecurityLevel);
|
||||||
|
|
||||||
|
if (!parentCommand && strlen(command->Name)==0)
|
||||||
|
sLog.outError("Subcommand '' at top level");
|
||||||
|
|
||||||
|
if (command->ChildCommands)
|
||||||
|
{
|
||||||
|
if (parentCommand && strlen(command->Name)==0)
|
||||||
|
sLog.outError("Subcommand '' of command '%s' have subcommands", parentCommand->Name);
|
||||||
|
|
||||||
|
CheckIntergrity(command->ChildCommands, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search (sub)command for command line available for chat handler access level
|
||||||
|
*
|
||||||
|
* @param text Command line string that will parsed for (sub)command search
|
||||||
|
*
|
||||||
|
* @return Pointer to found command structure or NULL if appropriate command not found
|
||||||
|
*/
|
||||||
|
ChatCommand const* ChatHandler::FindCommand(char const* text)
|
||||||
|
{
|
||||||
|
ChatCommand* command = NULL;
|
||||||
|
char const* textPtr = text;
|
||||||
|
|
||||||
|
return FindCommand(getCommandTable(), textPtr, command) == CHAT_COMMAND_OK ? command : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search (sub)command for command line available for chat handler access level with options and fail case additional info
|
||||||
|
*
|
||||||
|
* @param table Pointer to command C-style array first level command where will be searched
|
||||||
|
* @param text Command line string that will parsed for (sub)command search,
|
||||||
|
* it modified at return from function and pointed to not parsed tail
|
||||||
|
* @param command At success this is found command, at other cases this is last found parent command
|
||||||
|
* before subcommand search fail
|
||||||
|
* @param parentCommand Output arg for optional return parent command for command arg.
|
||||||
|
* @param cmdNamePtr Output arg for optional return last parsed command name.
|
||||||
|
* @param allAvailable Optional arg (with false default value) control use command access level checks while command search.
|
||||||
|
*
|
||||||
|
* @return one from enum value of ChatCommandSearchResult. Output args return values highly dependent from this return result:
|
||||||
|
*
|
||||||
|
* CHAT_COMMAND_OK - Command found!
|
||||||
|
* text point to non parsed tail with possible command specific data, command store found command pointer,
|
||||||
|
* parentCommand have parent of found command or NULL if command found in table array directly
|
||||||
|
* cmdNamePtr store found command name in original form from command line
|
||||||
|
* CHAT_COMMAND_UNKNOWN - Command not found in table directly
|
||||||
|
* text only skip possible whitespaces,
|
||||||
|
* command is NULL
|
||||||
|
* parentCommand is NULL
|
||||||
|
* cmdNamePtr store command name that not found as it extracted from command line
|
||||||
|
* CHAT_COMMAND_UNKNOWN_SUBCOMMAND - Subcommand not found in some deed subcomand lists
|
||||||
|
* text point to non parsed tail including not found command name in command line,
|
||||||
|
* command store last found parent command if any
|
||||||
|
* parentCommand have parent of command in command arg or NULL
|
||||||
|
* cmdNamePtr store command name that not found as it extracted from command line
|
||||||
|
*/
|
||||||
|
ChatCommandSearchResult ChatHandler::FindCommand(ChatCommand* table, char const* &text, ChatCommand*& command, ChatCommand** parentCommand /*= NULL*/, std::string* cmdNamePtr /*= NULL*/, bool allAvailable /*= false*/)
|
||||||
{
|
{
|
||||||
char const* oldtext = text;
|
|
||||||
std::string cmd = "";
|
std::string cmd = "";
|
||||||
|
|
||||||
|
// skip whitespaces
|
||||||
while (*text != ' ' && *text != '\0')
|
while (*text != ' ' && *text != '\0')
|
||||||
{
|
{
|
||||||
cmd += *text;
|
cmd += *text;
|
||||||
|
|
@ -894,37 +964,111 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, co
|
||||||
|
|
||||||
while (*text == ' ') ++text;
|
while (*text == ' ') ++text;
|
||||||
|
|
||||||
|
// search first level command in table
|
||||||
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
||||||
{
|
{
|
||||||
if( !hasStringAbbr(table[i].Name, cmd.c_str()) )
|
if (!hasStringAbbr(table[i].Name, cmd.c_str()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// select subcommand from child commands list
|
// select subcommand from child commands list
|
||||||
if(table[i].ChildCommands != NULL)
|
if (table[i].ChildCommands != NULL)
|
||||||
{
|
{
|
||||||
if(!ExecuteCommandInTable(table[i].ChildCommands, text, fullcmd))
|
char const* oldchildtext = text;
|
||||||
{
|
ChatCommand* parentSubcommand = NULL;
|
||||||
if(text && text[0] != '\0')
|
ChatCommandSearchResult res = FindCommand(table[i].ChildCommands, text, command, &parentSubcommand, cmdNamePtr, allAvailable);
|
||||||
SendSysMessage(LANG_NO_SUBCMD);
|
|
||||||
else
|
|
||||||
SendSysMessage(LANG_CMD_SYNTAX);
|
|
||||||
|
|
||||||
ShowHelpForCommand(table[i].ChildCommands,text);
|
switch(res)
|
||||||
SetSentErrorMessage(true);
|
{
|
||||||
|
case CHAT_COMMAND_OK:
|
||||||
|
{
|
||||||
|
// if subcommand success search not return parent command, then this parent command is owner of child commands
|
||||||
|
if (parentCommand)
|
||||||
|
*parentCommand = parentSubcommand ? parentSubcommand : &table[i];
|
||||||
|
|
||||||
|
// Name == "" is special case: restore original command text for next level "" (where parentSubcommand==NULL)
|
||||||
|
if (strlen(command->Name)==0 && !parentSubcommand)
|
||||||
|
text = oldchildtext;
|
||||||
|
|
||||||
|
return CHAT_COMMAND_OK;
|
||||||
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN:
|
||||||
|
{
|
||||||
|
// command not found directly in child command list, return child command list owner
|
||||||
|
command = &table[i];
|
||||||
|
*parentCommand = NULL; // we don't known parent of table list at this point
|
||||||
|
|
||||||
|
text = oldchildtext; // restore text to stated just after parse found parent command
|
||||||
|
return CHAT_COMMAND_UNKNOWN_SUBCOMMAND; // we not found subcommand for table[i]
|
||||||
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// some deep subcommand not found, if this second level subcommand then parentCommand can be NULL, use known value for it
|
||||||
|
if (parentCommand)
|
||||||
|
*parentCommand = parentSubcommand ? parentSubcommand : &table[i];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// must be available (not checked for subcommands case because parent command expected have most low access that all subcommands always
|
||||||
}
|
if (!allAvailable && !isAvailable(table[i]))
|
||||||
|
|
||||||
// must be available and have handler
|
|
||||||
if(!table[i].Handler || !isAvailable(table[i]))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SetSentErrorMessage(false);
|
// must be have handler is explicitly selected
|
||||||
// table[i].Name == "" is special case: send original command to handler
|
if (!table[i].Handler)
|
||||||
if((this->*(table[i].Handler))(strlen(table[i].Name)!=0 ? text : oldtext))
|
continue;
|
||||||
|
|
||||||
|
// command found directly in to table
|
||||||
|
command = &table[i];
|
||||||
|
|
||||||
|
// unknown table owner at this point
|
||||||
|
if (parentCommand)
|
||||||
|
*parentCommand = NULL;
|
||||||
|
|
||||||
|
if (cmdNamePtr)
|
||||||
|
*cmdNamePtr = cmd;
|
||||||
|
|
||||||
|
return CHAT_COMMAND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// command not found in table directly
|
||||||
|
command = NULL;
|
||||||
|
|
||||||
|
// unknown table owner at this point
|
||||||
|
if (parentCommand)
|
||||||
|
*parentCommand = NULL;
|
||||||
|
|
||||||
|
if (cmdNamePtr)
|
||||||
|
*cmdNamePtr = cmd;
|
||||||
|
|
||||||
|
return CHAT_COMMAND_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute (sub)command available for chat handler access level with options in command line string
|
||||||
|
*
|
||||||
|
* @param text Command line string that will parsed for (sub)command search and command specific data
|
||||||
|
*
|
||||||
|
* Command output and errors in command execution will send to chat handler.
|
||||||
|
*/
|
||||||
|
void ChatHandler::ExecuteCommand(const char* text)
|
||||||
|
{
|
||||||
|
std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing.
|
||||||
|
|
||||||
|
ChatCommand* command = NULL;
|
||||||
|
ChatCommand* parentCommand = NULL;
|
||||||
|
|
||||||
|
ChatCommandSearchResult res = FindCommand(getCommandTable(), text, command, &parentCommand);
|
||||||
|
|
||||||
|
switch(res)
|
||||||
{
|
{
|
||||||
if(table[i].SecurityLevel > SEC_PLAYER)
|
case CHAT_COMMAND_OK:
|
||||||
|
{
|
||||||
|
SetSentErrorMessage(false);
|
||||||
|
if ((this->*(command->Handler))(text))
|
||||||
|
{
|
||||||
|
if (command->SecurityLevel > SEC_PLAYER)
|
||||||
{
|
{
|
||||||
// chat case
|
// chat case
|
||||||
if (m_session)
|
if (m_session)
|
||||||
|
|
@ -943,112 +1087,200 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// some commands have custom error messages. Don't send the default one in these cases.
|
// some commands have custom error messages. Don't send the default one in these cases.
|
||||||
else if(!HasSentErrorMessage())
|
else if (!HasSentErrorMessage())
|
||||||
{
|
{
|
||||||
if(!table[i].Help.empty())
|
if (!command->Help.empty())
|
||||||
SendSysMessage(table[i].Help.c_str());
|
SendSysMessage(command->Help.c_str());
|
||||||
else
|
else
|
||||||
SendSysMessage(LANG_CMD_SYNTAX);
|
SendSysMessage(LANG_CMD_SYNTAX);
|
||||||
|
|
||||||
|
if (ChatCommand* showCommand = (strlen(command->Name)==0 && parentCommand ? parentCommand : command))
|
||||||
|
if (ChatCommand* childs = showCommand->ChildCommands)
|
||||||
|
ShowHelpForSubCommands(childs, showCommand->Name);
|
||||||
|
|
||||||
SetSentErrorMessage(true);
|
SetSentErrorMessage(true);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
return true;
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
|
||||||
|
{
|
||||||
|
SendSysMessage(LANG_NO_SUBCMD);
|
||||||
|
ShowHelpForCommand(command->ChildCommands,text);
|
||||||
|
SetSentErrorMessage(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN:
|
||||||
|
{
|
||||||
|
SendSysMessage(LANG_NO_CMD);
|
||||||
|
SetSentErrorMessage(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHandler::SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand )
|
/**
|
||||||
|
* Function find appropriate command and update command security level and help text
|
||||||
|
*
|
||||||
|
* @param commandTable Table for first level command search
|
||||||
|
* @param text Command line string that will parsed for (sub)command search
|
||||||
|
* @param security New security level for command
|
||||||
|
* @param help New help text for command
|
||||||
|
*
|
||||||
|
* @return true if command has been found, and false in other case
|
||||||
|
*
|
||||||
|
* All problems found while command search and updated output as to DB errors log
|
||||||
|
*/
|
||||||
|
bool ChatHandler::SetDataForCommandInTable(ChatCommand *commandTable, const char* text, uint32 security, std::string const& help)
|
||||||
{
|
{
|
||||||
std::string cmd = "";
|
std::string fullcommand = text; // original `text` can't be used. It content destroyed in command code processing.
|
||||||
|
|
||||||
while (*text != ' ' && *text != '\0')
|
ChatCommand* command = NULL;
|
||||||
|
std::string cmdName;
|
||||||
|
|
||||||
|
ChatCommandSearchResult res = FindCommand(commandTable, text, command, NULL, &cmdName, true);
|
||||||
|
|
||||||
|
switch(res)
|
||||||
{
|
{
|
||||||
cmd += *text;
|
case CHAT_COMMAND_OK:
|
||||||
++text;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*text == ' ') ++text;
|
|
||||||
|
|
||||||
for(uint32 i = 0; table[i].Name != NULL; i++)
|
|
||||||
{
|
{
|
||||||
// for data fill use full explicit command names
|
if (command->SecurityLevel != security)
|
||||||
if( table[i].Name != cmd )
|
DETAIL_LOG("Table `command` overwrite for command '%s' default security (%u) by %u",
|
||||||
continue;
|
fullcommand.c_str(),command->SecurityLevel,security);
|
||||||
|
|
||||||
// select subcommand from child commands list (including "")
|
command->SecurityLevel = security;
|
||||||
if(table[i].ChildCommands != NULL)
|
command->Help = help;
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.",text,fullcommand.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(table[i].SecurityLevel != security)
|
|
||||||
DETAIL_LOG("Table `command` overwrite for command '%s' default security (%u) by %u",fullcommand.c_str(),table[i].SecurityLevel,security);
|
|
||||||
|
|
||||||
table[i].SecurityLevel = security;
|
|
||||||
table[i].Help = help;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
|
||||||
// in case "" command let process by caller
|
|
||||||
if(!cmd.empty())
|
|
||||||
{
|
{
|
||||||
if(table==getCommandTable())
|
sLog.outErrorDb("Table `command` have unexpected subcommand '%s' in command '%s', skip.", cmdName.c_str(), fullcommand.c_str());
|
||||||
sLog.outErrorDb("Table `command` have not existed command '%s', skip.",cmd.c_str());
|
return false;
|
||||||
else
|
}
|
||||||
sLog.outErrorDb("Table `command` have not existed subcommand '%s' in command '%s', skip.",cmd.c_str(),fullcommand.c_str());
|
case CHAT_COMMAND_UNKNOWN:
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `command` have not existed command '%s', skip.", cmdName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ChatHandler::ParseCommands(const char* text)
|
bool ChatHandler::ParseCommands(const char* text)
|
||||||
{
|
{
|
||||||
ASSERT(text);
|
ASSERT(text);
|
||||||
ASSERT(*text);
|
ASSERT(*text);
|
||||||
|
|
||||||
//if(m_session->GetSecurity() == 0)
|
//if(m_session->GetSecurity() == SEC_PLAYER)
|
||||||
// return 0;
|
// return false;
|
||||||
|
|
||||||
/// chat case (.command or !command format)
|
/// chat case (.command or !command format)
|
||||||
if (m_session)
|
if (m_session)
|
||||||
{
|
{
|
||||||
if(text[0] != '!' && text[0] != '.')
|
if(text[0] != '!' && text[0] != '.')
|
||||||
return 0;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
/// ignore single . and ! in line
|
/// ignore single . and ! in line
|
||||||
if (strlen(text) < 2)
|
if (strlen(text) < 2)
|
||||||
return 0;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// ignore messages staring from many dots.
|
/// ignore messages staring from many dots.
|
||||||
if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
|
if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
/// skip first . or ! (in console allowed use command with . and ! and without its)
|
/// skip first . or ! (in console allowed use command with . and ! and without its)
|
||||||
if (text[0] == '!' || text[0] == '.')
|
if (text[0] == '!' || text[0] == '.')
|
||||||
++text;
|
++text;
|
||||||
|
|
||||||
std::string fullcmd = text; // original `text` can't be used. It content destroyed in command code processing.
|
ExecuteCommand(text);
|
||||||
|
|
||||||
if (!ExecuteCommandInTable(getCommandTable(), text, fullcmd))
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd)
|
||||||
|
{
|
||||||
|
std::string list;
|
||||||
|
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
||||||
{
|
{
|
||||||
SendSysMessage(LANG_NO_CMD);
|
// must be available (ignore handler existence for show command with possible available subcommands
|
||||||
SetSentErrorMessage(true);
|
if (!isAvailable(table[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_session)
|
||||||
|
list += "\n ";
|
||||||
|
else
|
||||||
|
list += "\n\r ";
|
||||||
|
|
||||||
|
list += table[i].Name;
|
||||||
|
|
||||||
|
if (table[i].ChildCommands)
|
||||||
|
list += " ...";
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
if (list.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (table==getCommandTable())
|
||||||
|
{
|
||||||
|
SendSysMessage(LANG_AVIABLE_CMD);
|
||||||
|
PSendSysMessage("%s",list.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PSendSysMessage(LANG_SUBCMDS_LIST,cmd,list.c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd)
|
||||||
|
{
|
||||||
|
char const* oldCmd = cmd;
|
||||||
|
ChatCommand* command = NULL;
|
||||||
|
ChatCommand* parentCommand = NULL;
|
||||||
|
|
||||||
|
ChatCommand* showCommand = NULL;
|
||||||
|
ChatCommand* childCommands = NULL;
|
||||||
|
|
||||||
|
ChatCommandSearchResult res = FindCommand(table, cmd, command, &parentCommand);
|
||||||
|
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case CHAT_COMMAND_OK:
|
||||||
|
{
|
||||||
|
// for "" subcommand use parent command if any for subcommands list output
|
||||||
|
if (strlen(command->Name) == 0 && parentCommand)
|
||||||
|
{
|
||||||
|
showCommand = parentCommand;
|
||||||
|
cmd = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
showCommand = command;
|
||||||
|
|
||||||
|
childCommands = showCommand->ChildCommands;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHAT_COMMAND_UNKNOWN_SUBCOMMAND:
|
||||||
|
showCommand = command;
|
||||||
|
childCommands = showCommand->ChildCommands;
|
||||||
|
break;
|
||||||
|
case CHAT_COMMAND_UNKNOWN:
|
||||||
|
// not show command list at error in first level command find fail
|
||||||
|
childCommands = table != getCommandTable() || strlen(oldCmd) == 0 ? table : NULL;
|
||||||
|
command = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command && !command->Help.empty())
|
||||||
|
SendSysMessage(command->Help.c_str());
|
||||||
|
|
||||||
|
if (childCommands)
|
||||||
|
if (ShowHelpForSubCommands(childCommands, showCommand ? showCommand->Name : ""))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (command && command->Help.empty())
|
||||||
|
SendSysMessage(LANG_NO_HELP_CMD);
|
||||||
|
|
||||||
|
return command || childCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHandler::isValidChatMessage(const char* message)
|
bool ChatHandler::isValidChatMessage(const char* message)
|
||||||
|
|
@ -1608,101 +1840,6 @@ valid examples:
|
||||||
return validSequence == validSequenceIterator;
|
return validSequence == validSequenceIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd)
|
|
||||||
{
|
|
||||||
std::string list;
|
|
||||||
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
|
||||||
{
|
|
||||||
// must be available (ignore handler existence for show command with possibe avalable subcomands
|
|
||||||
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)
|
|
||||||
list += " ...";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(list.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(table==getCommandTable())
|
|
||||||
{
|
|
||||||
SendSysMessage(LANG_AVIABLE_CMD);
|
|
||||||
PSendSysMessage("%s",list.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
PSendSysMessage(LANG_SUBCMDS_LIST,cmd,list.c_str());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd)
|
|
||||||
{
|
|
||||||
if(*cmd)
|
|
||||||
{
|
|
||||||
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
|
||||||
{
|
|
||||||
// must be available (ignore handler existence for show command with possibe avalable subcomands
|
|
||||||
if(!isAvailable(table[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( !hasStringAbbr(table[i].Name, cmd) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// have subcommand
|
|
||||||
char const* subcmd = (*cmd) ? strtok(NULL, " ") : "";
|
|
||||||
|
|
||||||
if(table[i].ChildCommands && 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)
|
|
||||||
if(ShowHelpForSubCommands(table[i].ChildCommands,table[i].Name,subcmd ? subcmd : ""))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !table[i].Help.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(uint32 i = 0; table[i].Name != NULL; ++i)
|
|
||||||
{
|
|
||||||
// must be available (ignore handler existence for show command with possibe avalable subcomands
|
|
||||||
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)
|
|
||||||
if(ShowHelpForSubCommands(table[i].ChildCommands,"",""))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !table[i].Help.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ShowHelpForSubCommands(table,"",cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored)
|
//Note: target_guid used only in CHAT_MSG_WHISPER_INFORM mode (in this case channelName ignored)
|
||||||
void ChatHandler::FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker)
|
void ChatHandler::FillMessageData( WorldPacket *data, WorldSession* session, uint8 type, uint32 language, const char *channelName, uint64 target_guid, const char *message, Unit *speaker)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,13 @@ class ChatCommand
|
||||||
ChatCommand * ChildCommands;
|
ChatCommand * ChildCommands;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ChatCommandSearchResult
|
||||||
|
{
|
||||||
|
CHAT_COMMAND_OK, // found accessible command by command string
|
||||||
|
CHAT_COMMAND_UNKNOWN, // first level command not found
|
||||||
|
CHAT_COMMAND_UNKNOWN_SUBCOMMAND, // command found but some level subcommand not find in subcommand list
|
||||||
|
};
|
||||||
|
|
||||||
class ChatHandler
|
class ChatHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -68,7 +75,8 @@ class ChatHandler
|
||||||
void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3);
|
void PSendSysMessage( const char *format, ...) ATTR_PRINTF(2,3);
|
||||||
void PSendSysMessage( int32 entry, ... );
|
void PSendSysMessage( int32 entry, ... );
|
||||||
|
|
||||||
int ParseCommands(const char* text);
|
bool ParseCommands(const char* text);
|
||||||
|
ChatCommand const* FindCommand(char const* text);
|
||||||
|
|
||||||
bool isValidChatMessage(const char* msg);
|
bool isValidChatMessage(const char* msg);
|
||||||
bool HasSentErrorMessage() { return sentErrorMessage;}
|
bool HasSentErrorMessage() { return sentErrorMessage;}
|
||||||
|
|
@ -91,11 +99,13 @@ class ChatHandler
|
||||||
|
|
||||||
void SendGlobalSysMessage(const char *str);
|
void SendGlobalSysMessage(const char *str);
|
||||||
|
|
||||||
bool SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand );
|
bool SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help);
|
||||||
bool ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcommand);
|
void ExecuteCommand(const char* text);
|
||||||
bool ShowHelpForCommand(ChatCommand *table, const char* cmd);
|
bool ShowHelpForCommand(ChatCommand *table, const char* cmd);
|
||||||
bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd);
|
bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd);
|
||||||
|
ChatCommandSearchResult FindCommand(ChatCommand* table, char const*& text, ChatCommand*& command, ChatCommand** parentCommand = NULL, std::string* cmdNamePtr = NULL, bool allAvailable = false);
|
||||||
|
|
||||||
|
void CheckIntergrity(ChatCommand *table, ChatCommand *parentCommand);
|
||||||
ChatCommand* getCommandTable();
|
ChatCommand* getCommandTable();
|
||||||
|
|
||||||
bool HandleAccountCommand(const char* args);
|
bool HandleAccountCommand(const char* args);
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
@ -236,7 +236,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
@ -270,7 +270,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
@ -292,7 +292,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
@ -314,7 +314,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
@ -344,7 +344,7 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
|
||||||
if(msg.empty())
|
if(msg.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
|
if (ChatHandler(this).ParseCommands(msg.c_str()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
|
||||||
|
|
|
||||||
|
|
@ -32,16 +32,15 @@
|
||||||
|
|
||||||
bool ChatHandler::HandleHelpCommand(const char* args)
|
bool ChatHandler::HandleHelpCommand(const char* args)
|
||||||
{
|
{
|
||||||
char* cmd = strtok((char*)args, " ");
|
if(!*args)
|
||||||
if(!cmd)
|
|
||||||
{
|
{
|
||||||
ShowHelpForCommand(getCommandTable(), "help");
|
ShowHelpForCommand(getCommandTable(), "help");
|
||||||
ShowHelpForCommand(getCommandTable(), "");
|
ShowHelpForCommand(getCommandTable(), "");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(!ShowHelpForCommand(getCommandTable(), cmd))
|
if (!ShowHelpForCommand(getCommandTable(), args))
|
||||||
SendSysMessage(LANG_NO_HELP_CMD);
|
SendSysMessage(LANG_NO_CMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -53,8 +52,12 @@ bool ChatHandler::HandleCommandsCommand(const char* /*args*/)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatHandler::HandleAccountCommand(const char* /*args*/)
|
bool ChatHandler::HandleAccountCommand(const char* args)
|
||||||
{
|
{
|
||||||
|
// let show subcommands at unexpected data in args
|
||||||
|
if (*args)
|
||||||
|
return false;
|
||||||
|
|
||||||
AccountTypes gmlevel = GetAccessLevel();
|
AccountTypes gmlevel = GetAccessLevel();
|
||||||
PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel));
|
PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel));
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "10241"
|
#define REVISION_NR "10242"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue