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
186: _name{}, _invoker {}, _permission{}, _help{}, _subCommands{} { }
std::string _name
Definition ChatCommand.h:202
CommandInvoker _invoker
Definition ChatCommand.h:203
std::variant< std::monostate, AcoreStrings, std::string > _help
Definition ChatCommand.h:205
std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > _subCommands
Definition ChatCommand.h:206
CommandPermissions _permission
Definition ChatCommand.h:204

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

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
71{
72 if (COMMAND_MAP.empty())
74
75 return COMMAND_MAP;
76}
static ChatSubCommandMap COMMAND_MAP
Definition ChatCommand.cpp:69
static void LoadCommandMap()
Definition ChatCommand.cpp:82

References COMMAND_MAP.

◆ HasVisibleSubCommands()

bool Acore::Impl::ChatCommands::ChatCommandNode::HasVisibleSubCommands ( ChatHandler const &  who) const
private
527{
528 for (auto it = _subCommands.begin(); it != _subCommands.end(); ++it)
529 if (it->second.IsVisible(who))
530 return true;
531
532 return false;
533}

Referenced by IsVisible().

◆ InvalidateCommandMap()

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

References COMMAND_MAP.

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

◆ IsInvokerVisible()

bool Acore::Impl::ChatCommands::ChatCommandNode::IsInvokerVisible ( ChatHandler const &  who) const
private
506{
507 if (!_invoker)
508 return false;
509
510 if (!sScriptMgr->OnBeforeIsInvokerVisible(_name, _permission, who))
511 return true;
512
514 return false;
515
517 return true;
518
519 // RBAC permissions start at 200, SEC_* levels are 0-4
521 return who.HasPermission(_permission.RequiredLevel);
522
523 return !who.IsConsole() && who.IsAvailable(_permission.RequiredLevel);
524}
#define sScriptMgr
Definition ScriptMgr.h:737
@ RBAC_PERM_COMMAND_RBAC
Definition RBAC.h:113
uint32 RequiredLevel
Definition ChatCommand.h:170
Acore::ChatCommands::Console AllowConsole
Definition ChatCommand.h:171

References ChatHandler::HasPermission(), ChatHandler::IsAvailable(), ChatHandler::IsConsole(), Acore::ChatCommands::No, rbac::RBAC_PERM_COMMAND_RBAC, sScriptMgr, and Acore::ChatCommands::Yes.

Referenced by IsVisible(), and TryExecuteCommand().

◆ IsVisible()

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

References HasVisibleSubCommands(), and IsInvokerVisible().

◆ LoadCommandMap()

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

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

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
34{
35 if (std::holds_alternative<ChatCommandBuilder::InvokerEntry>(builder._data))
36 {
37 ASSERT(!_invoker, "Duplicate blank sub-command.");
38 AcoreStrings help;
39 std::tie(_invoker, help, _permission) = *(std::get<ChatCommandBuilder::InvokerEntry>(builder._data));
40 if (help)
41 _help.emplace<AcoreStrings>(help);
42 }
43 else
44 LoadCommandsIntoMap(this, _subCommands, std::get<ChatCommandBuilder::SubCommandEntry>(builder._data));
45}
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
141{
142 if (_invoker && std::holds_alternative<std::monostate>(_help))
143 LOG_WARN("sql.sql", "Table `command` is missing help text for command '{}'.", name);
144
145 _name = name;
146
147 for (auto& [subToken, cmd] : _subCommands)
148 {
149 std::string subName(name);
150 subName.push_back(COMMAND_DELIMITER);
151 subName.append(subToken);
152 cmd.ResolveNames(subName);
153 }
154}

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

◆ SendCommandHelp()

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

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
351{
352 ChatCommandNode const* cmd = nullptr;
353 ChatSubCommandMap const* map = &GetTopLevelMap();
354
355 for (std::string_view token : Acore::Tokenize(cmdStr, COMMAND_DELIMITER, false))
356 {
357 FilteredCommandListIterator it1(*map, handler, token);
358 if (!it1)
359 { /* no matching subcommands found */
360 if (cmd)
361 {
362 cmd->SendCommandHelp(handler);
363 handler.PSendSysMessage(LANG_SUBCMD_INVALID, cmd->_name, COMMAND_DELIMITER, token);
364 }
365 else
366 handler.PSendSysMessage(LANG_CMD_INVALID, token);
367 return;
368 }
369
370 if (!StringEqualI(it1->first, token))
371 { /* ok, so it1 points at a partially matching subcommand - let's see if there are others */
372 auto it2 = it1;
373 ++it2;
374
375 if (it2)
376 { /* there are multiple matching subcommands - print possibilities and return */
377 if (cmd)
378 handler.PSendSysMessage(LANG_SUBCMD_AMBIGUOUS, cmd->_name, COMMAND_DELIMITER, token);
379 else
380 handler.PSendSysMessage(LANG_CMD_AMBIGUOUS, token);
381
382 handler.PSendSysMessage(it1->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it1->first);
383 do
384 {
385 handler.PSendSysMessage(it2->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it2->first);
386 } while (++it2);
387
388 return;
389 }
390 }
391
392 cmd = &it1->second;
393 map = &cmd->_subCommands;
394 }
395
396 if (cmd)
397 cmd->SendCommandHelp(handler);
398 else if (cmdStr.empty())
399 {
400 FilteredCommandListIterator it(*map, handler, "");
401 if (!it)
402 return;
404 do
405 {
406 handler.PSendSysMessage(it->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it->second._name);
407 } while (++it);
408 }
409 else
410 handler.PSendSysMessage(LANG_CMD_INVALID, cmdStr);
411}
@ LANG_SUBCMD_INVALID
Definition Language.h:235
@ LANG_AVAILABLE_CMDS
Definition Language.h:41
@ LANG_CMD_AMBIGUOUS
Definition Language.h:236
@ 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
276{
277 ChatCommandNode const* cmd = nullptr;
278 ChatSubCommandMap const* map = &GetTopLevelMap();
279
280 while (!cmdStr.empty() && (cmdStr.front() == COMMAND_DELIMITER))
281 cmdStr.remove_prefix(1);
282
283 while (!cmdStr.empty() && (cmdStr.back() == COMMAND_DELIMITER))
284 cmdStr.remove_suffix(1);
285
286 std::string_view oldTail = cmdStr;
287 while (!oldTail.empty())
288 {
289 /* oldTail = token DELIMITER newTail */
290 auto [token, newTail] = tokenize(oldTail);
291 ASSERT(!token.empty());
292
293 FilteredCommandListIterator it1(*map, handler, token);
294 if (!it1)
295 break; /* no matching subcommands found */
296
297 if (!StringEqualI(it1->first, token))
298 { /* ok, so it1 points at a partially matching subcommand - let's see if there are others */
299 auto it2 = it1;
300 ++it2;
301
302 if (it2)
303 { /* there are multiple matching subcommands - print possibilities and return */
304 if (cmd)
305 handler.PSendSysMessage(LANG_SUBCMD_AMBIGUOUS, cmd->_name, COMMAND_DELIMITER, token);
306 else
307 handler.PSendSysMessage(LANG_CMD_AMBIGUOUS, token);
308
309 handler.PSendSysMessage(it1->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it1->first);
310 do
311 {
312 handler.PSendSysMessage(it2->second.HasVisibleSubCommands(handler) ? LANG_SUBCMDS_LIST_ENTRY_ELLIPSIS : LANG_SUBCMDS_LIST_ENTRY, it2->first);
313 } while (++it2);
314
315 return true;
316 }
317 }
318
319 /* now we matched exactly one subcommand, and it1 points to it; go down the rabbit hole */
320 cmd = &it1->second;
321 map = &cmd->_subCommands;
322
323 oldTail = newTail;
324 }
325
326 if (!sScriptMgr->OnTryExecuteCommand(handler, cmdStr))
327 return true;
328
329 /* if we matched a command at some point, invoke it */
330 if (cmd)
331 {
332 handler.SetSentErrorMessage(false);
333 if (cmd->IsInvokerVisible(handler) && cmd->_invoker(&handler, oldTail))
334 { /* invocation succeeded, log this */
335 if (!handler.IsConsole())
336 LogCommandUsage(*handler.GetSession(), cmdStr);
337 }
338 else if (!handler.HasSentErrorMessage()) /* invocation failed, we should show usage */
339 {
340 cmd->SendCommandHelp(handler);
341 handler.SetSentErrorMessage(true);
342 }
343
344 return true;
345 }
346
347 return false;
348}
static void LogCommandUsage(WorldSession const &session, std::string_view cmdStr)
Definition ChatCommand.cpp:156
WorldSession * GetSession()
Definition Chat.h:242
bool HasSentErrorMessage() const
Definition Chat.h:237
void SetSentErrorMessage(bool val)
Definition Chat.h:238
bool IsConsole() const
Definition Chat.h:240

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 Symbol 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

The documentation for this class was generated from the following files: