TrinityCore
Loading...
Searching...
No Matches
ChatCommand.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITY_CHATCOMMAND_H
19#define TRINITY_CHATCOMMAND_H
20
21#include "ChatCommandArgs.h"
22#include "ChatCommandTags.h"
23#include "Define.h"
24#include "Errors.h"
25#include "Language.h"
26#include "ObjectGuid.h"
27#include "Optional.h"
28#include "RBAC.h"
29#include "StringFormat.h"
30#include "Util.h"
31#include <cstddef>
32#include <map>
33#include <utility>
34#include <tuple>
35#include <type_traits>
36#include <variant>
37#include <vector>
38
39class ChatHandler;
40
42{
43 enum class Console : bool
44 {
45 No = false,
46 Yes = true
47 };
48
49 struct ChatCommandBuilder;
50 using ChatCommandTable = std::vector<ChatCommandBuilder>;
51}
52
54{
55 // forward declaration
56 // ConsumeFromOffset contains the bounds check for offset, then hands off to MultiConsumer
57 // the call stack is MultiConsumer -> ConsumeFromOffset -> MultiConsumer -> ConsumeFromOffset etc
58 // MultiConsumer goes into ArgInfo for parsing on each iteration
59 template <typename Tuple, size_t offset>
60 ChatCommandResult ConsumeFromOffset(Tuple&, ChatHandler const* handler, std::string_view args);
61
62 template <typename Tuple, typename NextType, size_t offset>
64 {
65 static ChatCommandResult TryConsumeTo(Tuple& tuple, ChatHandler const* handler, std::string_view args)
66 {
67 ChatCommandResult next = ArgInfo<NextType>::TryConsume(std::get<offset>(tuple), handler, args);
68 if (next)
69 return ConsumeFromOffset<Tuple, offset + 1>(tuple, handler, *next);
70 else
71 return next;
72 }
73 };
74
75 template <typename Tuple, typename NestedNextType, size_t offset>
76 struct MultiConsumer<Tuple, Optional<NestedNextType>, offset>
77 {
78 static ChatCommandResult TryConsumeTo(Tuple& tuple, ChatHandler const* handler, std::string_view args)
79 {
80 // try with the argument
81 auto& myArg = std::get<offset>(tuple);
82 myArg.emplace();
83
84 ChatCommandResult result1 = ArgInfo<NestedNextType>::TryConsume(myArg.value(), handler, args);
85 if (result1)
86 if ((result1 = ConsumeFromOffset<Tuple, offset + 1>(tuple, handler, *result1)))
87 return result1;
88 // try again omitting the argument
89 myArg = std::nullopt;
90 ChatCommandResult result2 = ConsumeFromOffset<Tuple, offset + 1>(tuple, handler, args);
91 if (result2)
92 return result2;
93 if (result1.HasErrorMessage() && result2.HasErrorMessage())
94 {
95 return Trinity::StringFormat("{} \"{}\"\n{} \"{}\"",
98 }
99 else if (result1.HasErrorMessage())
100 return result1;
101 else
102 return result2;
103 }
104 };
105
106 template <typename Tuple, size_t offset>
107 ChatCommandResult ConsumeFromOffset([[maybe_unused]] Tuple& tuple, [[maybe_unused]] ChatHandler const* handler, std::string_view args)
108 {
109 if constexpr (offset < std::tuple_size_v<Tuple>)
110 return MultiConsumer<Tuple, std::tuple_element_t<offset, Tuple>, offset>::TryConsumeTo(tuple, handler, args);
111 else if (!args.empty()) /* the entire string must be consumed */
112 return std::nullopt;
113 else
114 return args;
115 }
116
117 template <typename T> struct HandlerToTuple { static_assert(Trinity::dependant_false_v<T>, "Invalid command handler signature"); };
118 template <typename... Ts> struct HandlerToTuple<bool(ChatHandler*, Ts...)> { using type = std::tuple<ChatHandler*, std::remove_cvref_t<Ts>...>; };
119 template <typename T> using TupleType = typename HandlerToTuple<T>::type;
120
122 {
123 CommandInvoker() : _wrapper(nullptr), _handler(nullptr) {}
124 template <typename TypedHandler>
125 CommandInvoker(TypedHandler& handler)
126 {
127 _wrapper = [](void* handler, ChatHandler* chatHandler, std::string_view argsStr)
128 {
129 using Tuple = TupleType<TypedHandler>;
130
131 Tuple arguments;
132 std::get<0>(arguments) = chatHandler;
133 ChatCommandResult result = ConsumeFromOffset<Tuple, 1>(arguments, chatHandler, argsStr);
134 if (result)
135 return std::apply(reinterpret_cast<TypedHandler*>(handler), std::move(arguments));
136 else
137 {
138 if (result.HasErrorMessage())
139 SendErrorMessageToHandler(chatHandler, result.GetErrorMessage());
140 return false;
141 }
142 };
143 _handler = reinterpret_cast<void*>(handler);
144 }
145 CommandInvoker(bool(&handler)(ChatHandler*, char const*))
146 {
147 _wrapper = [](void* handler, ChatHandler* chatHandler, std::string_view argsStr)
148 {
149 // make a copy of the argument string
150 // legacy handlers can destroy input strings with strtok
151 std::string argsStrCopy(argsStr);
152 return reinterpret_cast<bool(*)(ChatHandler*, char const*)>(handler)(chatHandler, argsStrCopy.c_str());
153 };
154 _handler = reinterpret_cast<void*>(handler);
155 }
156
157 explicit operator bool() const { return (_wrapper != nullptr); }
158 bool operator()(ChatHandler* chatHandler, std::string_view args) const
159 {
161 return _wrapper(_handler, chatHandler, args);
162 }
163
164 private:
165 using wrapper_func = bool(void*, ChatHandler*, std::string_view);
167 void* _handler;
168 };
169
177
179 {
182
183 public:
184 static void LoadCommandMap();
185 static void InvalidateCommandMap();
186 static bool TryExecuteCommand(ChatHandler& handler, std::string_view cmd);
187 static void SendCommandHelpFor(ChatHandler& handler, std::string_view cmd);
188 static std::vector<std::string> GetAutoCompletionsFor(ChatHandler const& handler, std::string_view cmd);
189
191
192 private:
193 static std::map<std::string_view, ChatCommandNode, StringCompareLessI_T> const& GetTopLevelMap();
194 static void LoadCommandsIntoMap(ChatCommandNode* blank, std::map<std::string_view, ChatCommandNode, StringCompareLessI_T>& map, Trinity::ChatCommands::ChatCommandTable const& commands);
195
196 void LoadFromBuilder(ChatCommandBuilder const& builder);
198
199 void ResolveNames(std::string name);
200 void SendCommandHelp(ChatHandler& handler) const;
201
202 bool IsVisible(ChatHandler const& who) const { return (IsInvokerVisible(who) || HasVisibleSubCommands(who)); }
203 bool IsInvokerVisible(ChatHandler const& who) const;
204 bool HasVisibleSubCommands(ChatHandler const& who) const;
205
206 std::string _name;
209 std::variant<std::monostate, TrinityStrings, std::string> _help;
210 std::map<std::string_view, ChatCommandNode, StringCompareLessI_T> _subCommands;
211 };
212}
213
214namespace Trinity::ChatCommands
215{
217 {
220 {
221 template <typename T>
223 : _invoker{ handler }, _help{ help }, _permissions{ permission, allowConsole }
224 {}
225 InvokerEntry(InvokerEntry const&) = default;
227
231
232 auto operator*() const { return std::tie(_invoker, _help, _permissions); }
233 };
234 using SubCommandEntry = std::reference_wrapper<std::vector<ChatCommandBuilder> const>;
235
238
239 template <typename TypedHandler>
240 ChatCommandBuilder(char const* name, TypedHandler& handler, TrinityStrings help, rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
241 : _name{ ASSERT_NOTNULL(name) }, _data{ std::in_place_type<InvokerEntry>, handler, help, permission, allowConsole }
242 {}
243
244 template <typename TypedHandler>
245 ChatCommandBuilder(char const* name, TypedHandler& handler, rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
246 : ChatCommandBuilder(name, handler, TrinityStrings(), permission, allowConsole)
247 {}
248 ChatCommandBuilder(char const* name, std::vector<ChatCommandBuilder> const& subCommands)
249 : _name{ ASSERT_NOTNULL(name) }, _data{ std::in_place_type<SubCommandEntry>, subCommands }
250 {}
251
252 [[deprecated("char const* parameters to command handlers are deprecated; convert this to a typed argument handler instead")]]
253 ChatCommandBuilder(char const* name, bool(&handler)(ChatHandler*, char const*), rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
254 : ChatCommandBuilder(name, handler, TrinityStrings(), permission, allowConsole)
255 {}
256
257 template <typename TypedHandler>
258 [[deprecated("you are using the old-style command format; convert this to the new format ({ name, handler (not a pointer!), permission, Console::(Yes/No) })")]]
259 ChatCommandBuilder(char const* name, rbac::RBACPermissions permission, bool console, TypedHandler* handler, char const*)
260 : ChatCommandBuilder(name, *handler, TrinityStrings(), permission, static_cast<Trinity::ChatCommands::Console>(console))
261 {}
262
263 [[deprecated("you are using the old-style command format; convert this to the new format ({ name, subCommands })")]]
264 ChatCommandBuilder(char const* name, rbac::RBACPermissions, bool, std::nullptr_t, char const*, std::vector <ChatCommandBuilder> const& sub)
265 : ChatCommandBuilder(name, sub)
266 {}
267
268 private:
269 std::string_view _name;
270 std::variant<InvokerEntry, SubCommandEntry> _data;
271 };
272
275 TC_GAME_API bool TryExecuteCommand(ChatHandler& handler, std::string_view cmd);
276 TC_GAME_API void SendCommandHelpFor(ChatHandler& handler, std::string_view cmd);
277 TC_GAME_API std::vector<std::string> GetAutoCompletionsFor(ChatHandler const& handler, std::string_view cmd);
278}
279
280// backwards compatibility with old patches
281using ChatCommand [[deprecated("std::vector<ChatCommand> should be ChatCommandTable! (using namespace Trinity::ChatCommands)")]] = Trinity::ChatCommands::ChatCommandBuilder;
282
283#endif
#define TC_GAME_API
Definition Define.h:114
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
TrinityStrings
Definition Language.h:29
@ LANG_CMDPARSER_EITHER
Definition Language.h:1001
@ LANG_CMDPARSER_OR
Definition Language.h:1002
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
Role Based Access Control related classes definition.
void SendCommandHelp(ChatHandler &handler) const
std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > _subCommands
std::variant< std::monostate, TrinityStrings, std::string > _help
ChatCommandNode(ChatCommandNode &&other)=default
bool HasVisibleSubCommands(ChatHandler const &who) const
static void SendCommandHelpFor(ChatHandler &handler, std::string_view cmd)
void LoadFromBuilder(ChatCommandBuilder const &builder)
Trinity::ChatCommands::ChatCommandBuilder ChatCommandBuilder
static std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > const & GetTopLevelMap()
static void LoadCommandsIntoMap(ChatCommandNode *blank, std::map< std::string_view, ChatCommandNode, StringCompareLessI_T > &map, Trinity::ChatCommands::ChatCommandTable const &commands)
bool IsVisible(ChatHandler const &who) const
bool IsInvokerVisible(ChatHandler const &who) const
static std::vector< std::string > GetAutoCompletionsFor(ChatHandler const &handler, std::string_view cmd)
static bool TryExecuteCommand(ChatHandler &handler, std::string_view cmd)
TC_GAME_API std::vector< std::string > GetAutoCompletionsFor(ChatHandler const &handler, std::string_view cmd)
TC_GAME_API void SendCommandHelpFor(ChatHandler &handler, std::string_view cmd)
std::vector< ChatCommandBuilder > ChatCommandTable
Definition ChatCommand.h:50
TC_GAME_API bool TryExecuteCommand(ChatHandler &handler, std::string_view cmd)
TC_GAME_API void InvalidateCommandMap()
TC_GAME_API void LoadCommandMap()
typename HandlerToTuple< T >::type TupleType
TC_GAME_API char const * GetTrinityString(ChatHandler const *handler, TrinityStrings which)
ChatCommandResult ConsumeFromOffset(Tuple &, ChatHandler const *handler, std::string_view args)
TC_GAME_API void SendErrorMessageToHandler(ChatHandler *handler, std::string_view str)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
RBACPermissions
Definition RBAC.h:53
STL namespace.
InvokerEntry(T &handler, TrinityStrings help, rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
Trinity::Impl::ChatCommands::CommandInvoker _invoker
Trinity::Impl::ChatCommands::CommandPermissions _permissions
std::variant< InvokerEntry, SubCommandEntry > _data
std::reference_wrapper< std::vector< ChatCommandBuilder > const > SubCommandEntry
ChatCommandBuilder(char const *name, std::vector< ChatCommandBuilder > const &subCommands)
ChatCommandBuilder(char const *name, rbac::RBACPermissions permission, bool console, TypedHandler *handler, char const *)
ChatCommandBuilder(ChatCommandBuilder const &)=default
ChatCommandBuilder(char const *name, TypedHandler &handler, TrinityStrings help, rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
ChatCommandBuilder(ChatCommandBuilder &&)=default
ChatCommandBuilder(char const *name, rbac::RBACPermissions, bool, std::nullptr_t, char const *, std::vector< ChatCommandBuilder > const &sub)
ChatCommandBuilder(char const *name, TypedHandler &handler, rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
ChatCommandBuilder(char const *name, bool(&handler)(ChatHandler *, char const *), rbac::RBACPermissions permission, Trinity::ChatCommands::Console allowConsole)
bool operator()(ChatHandler *chatHandler, std::string_view args) const
bool(void *, ChatHandler *, std::string_view) wrapper_func
CommandInvoker(bool(&handler)(ChatHandler *, char const *))
Trinity::ChatCommands::Console AllowConsole
CommandPermissions(rbac::RBACPermissions perm, Trinity::ChatCommands::Console console)
std::tuple< ChatHandler *, std::remove_cvref_t< Ts >... > type
static ChatCommandResult TryConsumeTo(Tuple &tuple, ChatHandler const *handler, std::string_view args)
Definition ChatCommand.h:78
static ChatCommandResult TryConsumeTo(Tuple &tuple, ChatHandler const *handler, std::string_view args)
Definition ChatCommand.h:65