AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Acore::Impl::ChatCommands::ChatCommandNode Class Reference

#include "ChatCommand.h"

Public Member Functions

 ChatCommandNode ()
 

Static Public Member Functions

static void LoadCommandMap ()
 
static void InvalidateCommandMap ()
 
static bool TryExecuteCommand (ChatHandler &handler, std::string_view cmd)
 
static void SendCommandHelpFor (ChatHandler &handler, std::string_view cmd)
 
static std::vector< std::string > GetAutoCompletionsFor (ChatHandler const &handler, std::string_view cmd)
 

Private Types

using ChatCommandBuilder = Acore::ChatCommands::ChatCommandBuilder
 

Private Member Functions

void LoadFromBuilder (ChatCommandBuilder const &builder)
 
 ChatCommandNode (ChatCommandNode &&other)=default
 
void ResolveNames (std::string name)
 
void SendCommandHelp (ChatHandler &handler) const
 
bool IsVisible (ChatHandler const &who) const
 
bool IsInvokerVisible (ChatHandler const &who) const
 
bool HasVisibleSubCommands (ChatHandler const &who) const
 

Static Private Member Functions

static std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > const & GetTopLevelMap ()
 
static void LoadCommandsIntoMap (ChatCommandNode *blank, std::map< std::string_view, Acore::Impl::ChatCommands::ChatCommandNode, StringCompareLessI_T > &map, Acore::ChatCommands::ChatCommandTable const &commands)
 

Private Attributes

std::string _name
 
CommandInvoker _invoker
 
CommandPermissions _permission
 
std::variant< std::monostate, AcoreStrings, std::string > _help
 
std::map< std::string_view, ChatCommandNode, StringCompareLessI_T_subCommands
 

Friends

struct FilteredCommandListIterator
 

Detailed Description

Member Typedef Documentation

◆ ChatCommandBuilder

Constructor & Destructor Documentation

◆ ChatCommandNode() [1/2]

Acore::Impl::ChatCommands::ChatCommandNode::ChatCommandNode ( )
inline
189: _name{}, _invoker {}, _permission{}, _help{}, _subCommands{} { }
std::string _name
Definition: ChatCommand.h:205
CommandInvoker _invoker
Definition: ChatCommand.h:206
std::variant< std::monostate, AcoreStrings, std::string > _help
Definition: ChatCommand.h:208
std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > _subCommands
Definition: ChatCommand.h:209
CommandPermissions _permission
Definition: ChatCommand.h:207

◆ ChatCommandNode() [2/2]

Acore::Impl::ChatCommands::ChatCommandNode::ChatCommandNode ( ChatCommandNode &&  other)
privatedefault

Member Function Documentation

◆ GetAutoCompletionsFor()

std::vector< std::string > Acore::Impl::ChatCommands::ChatCommandNode::GetAutoCompletionsFor ( ChatHandler const &  handler,
std::string_view  cmd 
)
static
413{
414 std::string path;
415 ChatCommandNode const* cmd = nullptr;
416 ChatSubCommandMap const* map = &GetTopLevelMap();
417
418 while (!cmdStr.empty() && (cmdStr.front() == COMMAND_DELIMITER))
419 cmdStr.remove_prefix(1);
420
421 while (!cmdStr.empty() && (cmdStr.back() == COMMAND_DELIMITER))
422 cmdStr.remove_suffix(1);
423
424 std::string_view oldTail = cmdStr;
425 while (!oldTail.empty())
426 {
427 /* oldTail = token DELIMITER newTail */
428 auto [token, newTail] = tokenize(oldTail);
429 ASSERT(!token.empty());
430 FilteredCommandListIterator it1(*map, handler, token);
431 if (!it1)
432 break; /* no matching subcommands found */
433
434 if (!StringEqualI(it1->first, token))
435 { /* ok, so it1 points at a partially matching subcommand - let's see if there are others */
436 auto it2 = it1;
437 ++it2;
438
439 if (it2)
440 { /* there are multiple matching subcommands - terminate here and show possibilities */
441 std::vector<std::string> vec;
442 auto possibility = ([prefix = std::string_view(path), suffix = std::string_view(newTail)](std::string_view match)
443 {
444 if (prefix.empty())
445 {
446 return Acore::StringFormat("{}{}{}", match, COMMAND_DELIMITER, suffix);
447 }
448 else
449 {
450 return Acore::StringFormat("{}{}{}{}{}", prefix, COMMAND_DELIMITER, match, COMMAND_DELIMITER, suffix);
451 }
452 });
453
454 vec.emplace_back(possibility(it1->first));
455
456 do vec.emplace_back(possibility(it2->first));
457 while (++it2);
458
459 return vec;
460 }
461 }
462
463 /* now we matched exactly one subcommand, and it1 points to it; go down the rabbit hole */
464 if (path.empty())
465 path.assign(it1->first);
466 else
467 {
468 path = Acore::StringFormat("{}{}{}", path, COMMAND_DELIMITER, it1->first);
469 }
470 cmd = &it1->second;
471 map = &cmd->_subCommands;
472
473 oldTail = newTail;
474 }
475
476 if (!oldTail.empty())
477 { /* there is some trailing text, leave it as is */
478 if (cmd)
479 { /* if we matched a command at some point, auto-complete it */
480 return { Acore::StringFormat("{}{}{}", path, COMMAND_DELIMITER, oldTail) };
481 }
482 else
483 return {};
484 }
485 else
486 { /* offer all subcommands */
487 auto possibility = ([prefix = std::string_view(path)](std::string_view match)
488 {
489 if (prefix.empty())
490 return std::string(match);
491 else
492 {
493 return Acore::StringFormat("{}{}{}", prefix, COMMAND_DELIMITER, match);
494 }
495 });
496
497 std::vector<std::string> vec;
498 for (FilteredCommandListIterator it(*map, handler, ""); it; ++it)
499 vec.emplace_back(possibility(it->first));
500 return vec;
501 }
502}
bool StringEqualI(std::string_view a, std::string_view b)
Definition: Util.cpp:592
#define ASSERT
Definition: Errors.h:68
std::map< std::string_view, Acore::Impl::ChatCommands::ChatCommandNode, StringCompareLessI_T > ChatSubCommandMap
Definition: ChatCommand.cpp:30
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default AC string format function.
Definition: StringFormat.h:34
static constexpr char COMMAND_DELIMITER
Definition: ChatCommandHelpers.h:38
TokenizeResult tokenize(std::string_view args)
Definition: ChatCommandHelpers.h:55
friend struct FilteredCommandListIterator
Definition: ChatCommand.h:179
static std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > const & GetTopLevelMap()
Definition: ChatCommand.cpp:69
ChatCommandNode()
Definition: ChatCommand.h:189

References _subCommands, ASSERT, Acore::Impl::ChatCommands::COMMAND_DELIMITER, StringEqualI(), Acore::StringFormat(), and Acore::Impl::ChatCommands::tokenize().

Referenced by Acore::ChatCommands::GetAutoCompletionsFor().

◆ GetTopLevelMap()

ChatSubCommandMap const & Acore::Impl::ChatCommands::ChatCommandNode::GetTopLevelMap ( )
staticprivate
70{
71 if (COMMAND_MAP.empty())
73
74 return COMMAND_MAP;
75}
static ChatSubCommandMap COMMAND_MAP
Definition: ChatCommand.cpp:68
static void LoadCommandMap()
Definition: ChatCommand.cpp:81

References COMMAND_MAP.

◆ HasVisibleSubCommands()

bool Acore::Impl::ChatCommands::ChatCommandNode::HasVisibleSubCommands ( ChatHandler const &  who) const
private
519{
520 for (auto it = _subCommands.begin(); it != _subCommands.end(); ++it)
521 if (it->second.IsVisible(who))
522 return true;
523
524 return false;
525}

Referenced by IsVisible().

◆ InvalidateCommandMap()

void Acore::Impl::ChatCommands::ChatCommandNode::InvalidateCommandMap ( )
static
77{
78 COMMAND_MAP.clear();
79}

References COMMAND_MAP.

Referenced by Acore::ChatCommands::InvalidateCommandMap().

◆ IsInvokerVisible()

bool Acore::Impl::ChatCommands::ChatCommandNode::IsInvokerVisible ( ChatHandler const &  who) const
private
505{
506 if (!_invoker)
507 return false;
508
510 return false;
511
513 return true;
514
515 return !who.IsConsole() && who.IsAvailable(_permission.RequiredLevel);
516}
uint32 RequiredLevel
Definition: ChatCommand.h:173
Acore::ChatCommands::Console AllowConsole
Definition: ChatCommand.h:174

References ChatHandler::IsAvailable(), ChatHandler::IsConsole(), Acore::ChatCommands::No, and Acore::ChatCommands::Yes.

Referenced by IsVisible(), and TryExecuteCommand().

◆ IsVisible()

bool Acore::Impl::ChatCommands::ChatCommandNode::IsVisible ( ChatHandler const &  who) const
inlineprivate
201{ return (IsInvokerVisible(who) || HasVisibleSubCommands(who)); }
bool HasVisibleSubCommands(ChatHandler const &who) const
Definition: ChatCommand.cpp:518
bool IsInvokerVisible(ChatHandler const &who) const
Definition: ChatCommand.cpp:504

References HasVisibleSubCommands(), and IsInvokerVisible().

◆ LoadCommandMap()

void Acore::Impl::ChatCommands::ChatCommandNode::LoadCommandMap ( )
static
82{
84 LoadCommandsIntoMap(nullptr, COMMAND_MAP, sScriptMgr->GetChatCommands());
85
86 if (PreparedQueryResult result = WorldDatabase.Query(WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS)))
87 {
88 do
89 {
90 Field* fields = result->Fetch();
91 std::string_view const name = fields[0].Get<std::string_view>();
92 std::string_view const help = fields[2].Get<std::string_view>();
93 uint32 const secLevel = fields[1].Get<uint8>();
94
95 ChatCommandNode* cmd = nullptr;
97
98 for (std::string_view key : Acore::Tokenize(name, COMMAND_DELIMITER, false))
99 {
100 auto it = map->find(key);
101 if (it != map->end())
102 {
103 cmd = &it->second;
104 map = &cmd->_subCommands;
105 }
106 else
107 {
108 LOG_ERROR("sql.sql", "Table `command` contains data for non-existant command '{}'. Skipped.", name);
109 cmd = nullptr;
110 break;
111 }
112 }
113
114 if (!cmd)
115 continue;
116
117 if (cmd->_invoker && (cmd->_permission.RequiredLevel != secLevel))
118 {
119 LOG_WARN("sql.sql", "Table `command` has permission {} for '{}' which does not match the core ({}). Overriding.",
120 secLevel, name, cmd->_permission.RequiredLevel);
121
122 cmd->_permission.RequiredLevel = secLevel;
123 }
124
125 if (std::holds_alternative<std::string>(cmd->_help))
126 LOG_ERROR("sql.sql", "Table `command` contains duplicate data for command '{}'. Skipped.", name);
127
128 if (std::holds_alternative<std::monostate>(cmd->_help))
129 cmd->_help.emplace<std::string>(help);
130 else
131 LOG_ERROR("sql.sql", "Table `command` contains legacy help text for command '{}', which uses `acore_string`. Skipped.", name);
132 } while (result->NextRow());
133 }
134
135 for (auto& [name, cmd] : COMMAND_MAP)
136 cmd.ResolveNames(std::string(name));
137}
#define LOG_ERROR(filterType__,...)
Definition: Log.h:156
#define LOG_WARN(filterType__,...)
Definition: Log.h:160
std::uint8_t uint8
Definition: Define.h:109
std::uint32_t uint32
Definition: Define.h:107
#define sScriptMgr
Definition: ScriptMgr.h:708
std::shared_ptr< PreparedResultSet > PreparedQueryResult
Definition: DatabaseEnvFwd.h:45
@ WORLD_SEL_COMMANDS
Definition: WorldDatabase.h:84
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Tokenize.cpp:20
Class used to access individual fields of database query result.
Definition: Field.h:98
std::enable_if_t< std::is_arithmetic_v< T >, T > Get() const
Definition: Field.h:112
static void InvalidateCommandMap()
Definition: ChatCommand.cpp:76
static void LoadCommandsIntoMap(ChatCommandNode *blank, std::map< std::string_view, Acore::Impl::ChatCommands::ChatCommandNode, StringCompareLessI_T > &map, Acore::ChatCommands::ChatCommandTable const &commands)
Definition: ChatCommand.cpp:46

References Acore::Impl::ChatCommands::COMMAND_DELIMITER, COMMAND_MAP, Field::Get(), LOG_ERROR, LOG_WARN, sScriptMgr, Acore::Tokenize(), WORLD_SEL_COMMANDS, and WorldDatabase.

Referenced by Acore::ChatCommands::LoadCommandMap().

◆ LoadCommandsIntoMap()

void Acore::Impl::ChatCommands::ChatCommandNode::LoadCommandsIntoMap ( ChatCommandNode blank,
std::map< std::string_view, Acore::Impl::ChatCommands::ChatCommandNode, StringCompareLessI_T > &  map,
Acore::ChatCommands::ChatCommandTable const &  commands 
)
staticprivate
48{
49 for (ChatCommandBuilder const& builder : commands)
50 {
51 if (builder._name.empty())
52 {
53 ASSERT(blank, "Empty name command at top level is not permitted.");
54 blank->LoadFromBuilder(builder);
55 }
56 else
57 {
58 std::vector<std::string_view> const tokens = Acore::Tokenize(builder._name, COMMAND_DELIMITER, false);
59 ASSERT(!tokens.empty(), "Invalid command name '{}'.", builder._name);
60 ChatSubCommandMap* subMap = &map;
61 for (std::size_t i = 0, n = (tokens.size() - 1); i < n; ++i)
62 subMap = &((*subMap)[tokens[i]]._subCommands);
63 ((*subMap)[tokens.back()]).LoadFromBuilder(builder);
64 }
65 }
66}
void LoadFromBuilder(ChatCommandBuilder const &builder)
Definition: ChatCommand.cpp:32
Acore::ChatCommands::ChatCommandBuilder ChatCommandBuilder
Definition: ChatCommand.h:180

References ASSERT, Acore::Impl::ChatCommands::COMMAND_DELIMITER, LoadFromBuilder(), and Acore::Tokenize().

Referenced by LoadFromBuilder().

◆ LoadFromBuilder()

void Acore::Impl::ChatCommands::ChatCommandNode::LoadFromBuilder ( ChatCommandBuilder const &  builder)
private
33{
34 if (std::holds_alternative<ChatCommandBuilder::InvokerEntry>(builder._data))
35 {
36 ASSERT(!_invoker, "Duplicate blank sub-command.");
37 AcoreStrings help;
38 std::tie(_invoker, help, _permission) = *(std::get<ChatCommandBuilder::InvokerEntry>(builder._data));
39 if (help)
40 _help.emplace<AcoreStrings>(help);
41 }
42 else
43 LoadCommandsIntoMap(this, _subCommands, std::get<ChatCommandBuilder::SubCommandEntry>(builder._data));
44}
AcoreStrings
Definition: Language.h:29

References Acore::ChatCommands::ChatCommandBuilder::_data, _help, _invoker, _permission, _subCommands, ASSERT, and LoadCommandsIntoMap().

Referenced by LoadCommandsIntoMap().

◆ ResolveNames()

void Acore::Impl::ChatCommands::ChatCommandNode::ResolveNames ( std::string  name)
private
140{
141 if (_invoker && std::holds_alternative<std::monostate>(_help))
142 LOG_WARN("sql.sql", "Table `command` is missing help text for command '{}'.", name);
143
144 _name = name;
145
146 for (auto& [subToken, cmd] : _subCommands)
147 {
148 std::string subName(name);
149 subName.push_back(COMMAND_DELIMITER);
150 subName.append(subToken);
151 cmd.ResolveNames(subName);
152 }
153}

References Acore::Impl::ChatCommands::COMMAND_DELIMITER, and LOG_WARN.

◆ SendCommandHelp()

void Acore::Impl::ChatCommands::ChatCommandNode::SendCommandHelp ( ChatHandler handler) const
private
191{
192 bool const hasInvoker = IsInvokerVisible(handler);
193 if (hasInvoker)
194 {
195 if (std::holds_alternative<AcoreStrings>(_help))
196 handler.SendSysMessage(std::get<AcoreStrings>(_help));
197 else if (std::holds_alternative<std::string>(_help))
198 handler.SendSysMessage(std::get<std::string>(_help));
199 else
200 {
203 }
204 }
205
206 bool header = false;
207
208 for (auto it = _subCommands.begin(); it != _subCommands.end(); ++it)
209 {
210 bool const subCommandHasSubCommand = it->second.HasVisibleSubCommands(handler);
211
212 if (!subCommandHasSubCommand && !it->second.IsInvokerVisible(handler))
213 {
214 continue;
215 }
216
217 if (!header)
218 {
219 if (!hasInvoker)
220 {
222 }
223
225 header = true;
226 }
227
228 handler.PSendSysMessage(subCommandHasSubCommand ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it->second._name);
229 }
230}
@ LANG_CMD_NO_HELP_AVAILABLE
Definition: Language.h:230
@ LANG_SUBCMDS_LIST
Definition: Language.h:40
@ LANG_SUBCMDS_LIST_ENTRY
Definition: Language.h:225
@ LANG_CMD_HELP_GENERIC
Definition: Language.h:229
@ LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS
Definition: Language.h:226
void PSendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:213
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:162

References LANG_CMD_HELP_GENERIC, LANG_CMD_NO_HELP_AVAILABLE, LANG_SUBCMDS_LIST, LANG_SUBCMDS_LIST_ENTRY, LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS, ChatHandler::PSendSysMessage(), and ChatHandler::SendSysMessage().

Referenced by SendCommandHelpFor(), and TryExecuteCommand().

◆ SendCommandHelpFor()

void Acore::Impl::ChatCommands::ChatCommandNode::SendCommandHelpFor ( ChatHandler handler,
std::string_view  cmd 
)
static
350{
351 ChatCommandNode const* cmd = nullptr;
352 ChatSubCommandMap const* map = &GetTopLevelMap();
353
354 for (std::string_view token : Acore::Tokenize(cmdStr, COMMAND_DELIMITER, false))
355 {
356 FilteredCommandListIterator it1(*map, handler, token);
357 if (!it1)
358 { /* no matching subcommands found */
359 if (cmd)
360 {
361 cmd->SendCommandHelp(handler);
362 handler.PSendSysMessage(LANG_SUBCMD_INVALID, cmd->_name, COMMAND_DELIMITER, token);
363 }
364 else
365 handler.PSendSysMessage(LANG_CMD_INVALID, token);
366 return;
367 }
368
369 if (!StringEqualI(it1->first, token))
370 { /* ok, so it1 points at a partially matching subcommand - let's see if there are others */
371 auto it2 = it1;
372 ++it2;
373
374 if (it2)
375 { /* there are multiple matching subcommands - print possibilities and return */
376 if (cmd)
377 handler.PSendSysMessage(LANG_SUBCMD_AMBIGUOUS, cmd->_name, COMMAND_DELIMITER, token);
378 else
379 handler.PSendSysMessage(LANG_CMD_AMBIGUOUS, token);
380
381 handler.PSendSysMessage(it1->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it1->first);
382 do
383 {
384 handler.PSendSysMessage(it2->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it2->first);
385 } while (++it2);
386
387 return;
388 }
389 }
390
391 cmd = &it1->second;
392 map = &cmd->_subCommands;
393 }
394
395 if (cmd)
396 cmd->SendCommandHelp(handler);
397 else if (cmdStr.empty())
398 {
399 FilteredCommandListIterator it(*map, handler, "");
400 if (!it)
401 return;
403 do
404 {
405 handler.PSendSysMessage(it->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it->second._name);
406 } while (++it);
407 }
408 else
409 handler.PSendSysMessage(LANG_CMD_INVALID, cmdStr);
410}
@ LANG_SUBCMD_INVALID
Definition: Language.h:227
@ LANG_AVAILABLE_CMDS
Definition: Language.h:41
@ LANG_CMD_AMBIGUOUS
Definition: Language.h:228
@ LANG_CMD_INVALID
Definition: Language.h:38
@ LANG_SUBCMD_AMBIGUOUS
Definition: Language.h:39

References _name, _subCommands, Acore::Impl::ChatCommands::COMMAND_DELIMITER, LANG_AVAILABLE_CMDS, LANG_CMD_AMBIGUOUS, LANG_CMD_INVALID, LANG_SUBCMD_AMBIGUOUS, LANG_SUBCMD_INVALID, LANG_SUBCMDS_LIST_ENTRY, LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS, ChatHandler::PSendSysMessage(), SendCommandHelp(), ChatHandler::SendSysMessage(), StringEqualI(), and Acore::Tokenize().

Referenced by Acore::ChatCommands::SendCommandHelpFor().

◆ TryExecuteCommand()

bool Acore::Impl::ChatCommands::ChatCommandNode::TryExecuteCommand ( ChatHandler handler,
std::string_view  cmd 
)
static
275{
276 ChatCommandNode const* cmd = nullptr;
277 ChatSubCommandMap const* map = &GetTopLevelMap();
278
279 while (!cmdStr.empty() && (cmdStr.front() == COMMAND_DELIMITER))
280 cmdStr.remove_prefix(1);
281
282 while (!cmdStr.empty() && (cmdStr.back() == COMMAND_DELIMITER))
283 cmdStr.remove_suffix(1);
284
285 std::string_view oldTail = cmdStr;
286 while (!oldTail.empty())
287 {
288 /* oldTail = token DELIMITER newTail */
289 auto [token, newTail] = tokenize(oldTail);
290 ASSERT(!token.empty());
291
292 FilteredCommandListIterator it1(*map, handler, token);
293 if (!it1)
294 break; /* no matching subcommands found */
295
296 if (!StringEqualI(it1->first, token))
297 { /* ok, so it1 points at a partially matching subcommand - let's see if there are others */
298 auto it2 = it1;
299 ++it2;
300
301 if (it2)
302 { /* there are multiple matching subcommands - print possibilities and return */
303 if (cmd)
304 handler.PSendSysMessage(LANG_SUBCMD_AMBIGUOUS, cmd->_name, COMMAND_DELIMITER, token);
305 else
306 handler.PSendSysMessage(LANG_CMD_AMBIGUOUS, token);
307
308 handler.PSendSysMessage(it1->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it1->first);
309 do
310 {
311 handler.PSendSysMessage(it2->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it2->first);
312 } while (++it2);
313
314 return true;
315 }
316 }
317
318 /* now we matched exactly one subcommand, and it1 points to it; go down the rabbit hole */
319 cmd = &it1->second;
320 map = &cmd->_subCommands;
321
322 oldTail = newTail;
323 }
324
325 if (!sScriptMgr->OnTryExecuteCommand(handler, cmdStr))
326 return true;
327
328 /* if we matched a command at some point, invoke it */
329 if (cmd)
330 {
331 handler.SetSentErrorMessage(false);
332 if (cmd->IsInvokerVisible(handler) && cmd->_invoker(&handler, oldTail))
333 { /* invocation succeeded, log this */
334 if (!handler.IsConsole())
335 LogCommandUsage(*handler.GetSession(), cmdStr);
336 }
337 else if (!handler.HasSentErrorMessage()) /* invocation failed, we should show usage */
338 {
339 cmd->SendCommandHelp(handler);
340 handler.SetSentErrorMessage(true);
341 }
342
343 return true;
344 }
345
346 return false;
347}
static void LogCommandUsage(WorldSession const &session, std::string_view cmdStr)
Definition: ChatCommand.cpp:155
WorldSession * GetSession()
Definition: Chat.h:244
bool HasSentErrorMessage() const
Definition: Chat.h:239
void SetSentErrorMessage(bool val)
Definition: Chat.h:240
bool IsConsole() const
Definition: Chat.h:242

References _invoker, _name, _subCommands, ASSERT, Acore::Impl::ChatCommands::COMMAND_DELIMITER, ChatHandler::GetSession(), ChatHandler::HasSentErrorMessage(), ChatHandler::IsConsole(), IsInvokerVisible(), LANG_CMD_AMBIGUOUS, LANG_SUBCMD_AMBIGUOUS, LANG_SUBCMDS_LIST_ENTRY, LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS, LogCommandUsage(), ChatHandler::PSendSysMessage(), SendCommandHelp(), ChatHandler::SetSentErrorMessage(), sScriptMgr, StringEqualI(), and Acore::Impl::ChatCommands::tokenize().

Referenced by Acore::ChatCommands::TryExecuteCommand().

Friends And Related Function Documentation

◆ FilteredCommandListIterator

friend struct FilteredCommandListIterator
friend

Member Data Documentation

◆ _help

std::variant<std::monostate, AcoreStrings, std::string> Acore::Impl::ChatCommands::ChatCommandNode::_help
private

Referenced by LoadFromBuilder().

◆ _invoker

CommandInvoker Acore::Impl::ChatCommands::ChatCommandNode::_invoker
private

◆ _name

std::string Acore::Impl::ChatCommands::ChatCommandNode::_name
private

◆ _permission

CommandPermissions Acore::Impl::ChatCommands::ChatCommandNode::_permission
private

Referenced by LoadFromBuilder().

◆ _subCommands

std::map<std::string_view, ChatCommandNode, StringCompareLessI_T> Acore::Impl::ChatCommands::ChatCommandNode::_subCommands
private