TrinityCore
Loading...
Searching...
No Matches
ChatCommandArgs.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_CHATCOMMANDARGS_H
19#define TRINITY_CHATCOMMANDARGS_H
20
21#include "ChatCommandHelpers.h"
22#include "ChatCommandTags.h"
23#include "EnumFlag.h"
24#include "SmartEnum.h"
25#include "StringConvert.h"
26#include "StringFormat.h"
27#include "Util.h"
28#include <string>
29#include <string_view>
30#include <vector>
31
32struct GameTele;
33
35{
36
37 /************************** ARGUMENT HANDLERS *******************************************\
38 |* Define how to extract contents of a certain requested type from a string *|
39 |* Must implement the following: *|
40 |* - TryConsume: T&, ChatHandler const*, std::string_view -> ChatCommandResult *|
41 |* - on match, returns tail of the provided argument string (as std::string_view) *|
42 |* - on specific error, returns error message (as std::string&& or char const*) *|
43 |* - on generic error, returns std::nullopt (this will print command usage) *|
44 |* *|
45 |* - if a match is returned, T& should be initialized to the matched value *|
46 |* - otherwise, the state of T& is indeterminate and caller will not use it *|
47 |* *|
48 \****************************************************************************************/
49 template <typename T>
50 struct ArgInfo { static_assert(Trinity::dependant_false_v<T>, "Invalid command parameter type - see ChatCommandArgs.h for possible types"); };
51
52 TC_GAME_API void InvalidStringValueFormatError(ChatCommandResult& result, ChatHandler const* handler, std::string_view arg, std::type_info const& type) noexcept;
53
54 // catch-all for number types
55 template <typename T> requires std::is_arithmetic_v<T>
56 struct ArgInfo<T>
57 {
58 static ChatCommandResult TryConsume(T& val, ChatHandler const* handler, std::string_view args) noexcept
59 {
60 auto [token, tail] = tokenize(args);
61 ChatCommandResult result = std::nullopt;
62 if (token.empty())
63 return result;
64
65 Optional<T> v = StringTo<T>(token, 0);
66 if (!v)
67 {
68 InvalidStringValueFormatError(result, handler, token, typeid(T));
69 return result;
70 }
71
72 if constexpr (std::is_floating_point_v<T>)
73 {
74 if (!std::isfinite(val))
75 {
76 InvalidStringValueFormatError(result, handler, token, typeid(T));
77 return result;
78 }
79 }
80
81 val = *v;
82 result = tail;
83
84 return result;
85 }
86 };
87
88 // string_view
89 template <>
90 struct ArgInfo<std::string_view>
91 {
92 static ChatCommandResult TryConsume(std::string_view& val, ChatHandler const*, std::string_view args) noexcept
93 {
94 auto [token, next] = tokenize(args);
95 if (token.empty())
96 return std::nullopt;
97 val = token;
98 return next;
99 }
100 };
101
102 // string
103 template <>
104 struct ArgInfo<std::string>
105 {
106 static ChatCommandResult TryConsume(std::string& val, ChatHandler const* handler, std::string_view args) noexcept
107 {
108 std::string_view view;
110 if (next)
111 val.assign(view);
112 return next;
113 }
114 };
115
116 // wstring
117 template <>
118 struct ArgInfo<std::wstring>
119 {
120 static ChatCommandResult TryConsume(std::wstring& val, ChatHandler const* handler, std::string_view args) noexcept
121 {
122 std::string_view utf8view;
123 ChatCommandResult next = ArgInfo<std::string_view>::TryConsume(utf8view, handler, args);
124
125 if (next)
126 {
127 if (!Utf8toWStr(utf8view, val))
129 }
130 else
131 next = std::nullopt;
132
133 return next;
134 }
135 };
136
137 // enum
139 {
140 using SearchMap = std::vector<std::pair<std::string_view, Optional<int64>>>;
141
142 static void AddSearchMapEntry(SearchMap& map, int64 val, EnumText const& text) noexcept;
143
144 static int64 const* Match(SearchMap const& map, std::string_view s) noexcept;
145 };
146
147 template <typename T> requires std::is_enum_v<T>
148 struct ArgInfo<T> : EnumArgInfoBase
149 {
150 static SearchMap MakeSearchMap() noexcept
151 {
152 SearchMap map;
153 for (T val : EnumUtils::Iterate<T>())
155
156 return map;
157 }
158
159 static inline SearchMap const _map = MakeSearchMap();
160
161 static ChatCommandResult TryConsume(T& val, ChatHandler const* handler, std::string_view args) noexcept
162 {
163 std::string_view strVal;
164 ChatCommandResult next1 = ArgInfo<std::string_view>::TryConsume(strVal, handler, args);
165 if (next1)
166 {
167 if (int64 const* match = Match(_map, strVal))
168 {
169 val = static_cast<T>(*match);
170 return next1;
171 }
172 }
173
174 // Value not found. Try to parse arg as underlying type and cast it to enum type
175 do
176 {
177 using U = std::underlying_type_t<T>;
178 U uVal = 0;
179 if (ChatCommandResult next2 = ArgInfo<U>::TryConsume(uVal, handler, args))
180 {
181 // validate numeric value only if its not a flag to allow combined flags
182 if constexpr (!EnumTraits::IsFlag<T>::value)
183 if (!EnumUtils::IsValid<T>(uVal))
184 break;
185
186 val = static_cast<T>(uVal);
187 next1 = *next2;
188 return next1;
189 }
190 } while (false);
191
192 // We successfully parsed a token but it couldn't be converted to enum - replace it with error
193 if (next1)
194 InvalidStringValueFormatError(next1, handler, strVal, typeid(T));
195
196 return next1;
197 }
198 };
199
200 // a container tag
201 template <typename T> requires std::is_base_of_v<ContainerTag, T>
202 struct ArgInfo<T>
203 {
204 static ChatCommandResult TryConsume(T& tag, ChatHandler const* handler, std::string_view args) noexcept
205 {
206 return tag.TryConsume(handler, args);
207 }
208 };
209
210 // non-empty vector
211 template <typename T>
212 struct ArgInfo<std::vector<T>>
213 {
214 static ChatCommandResult TryConsume(std::vector<T>& val, ChatHandler const* handler, std::string_view args) noexcept
215 {
216 val.clear();
217 ChatCommandResult next = ArgInfo<T>::TryConsume(val.emplace_back(), handler, args);
218
219 if (!next)
220 return next;
221
222 while (ChatCommandResult next2 = ArgInfo<T>::TryConsume(val.emplace_back(), handler, *next))
223 next = std::move(next2);
224
225 val.pop_back();
226 return next;
227 }
228 };
229
230 // fixed-size array
231 template <typename T, size_t N>
232 struct ArgInfo<std::array<T, N>>
233 {
234 static ChatCommandResult TryConsume(std::array<T, N>& val, ChatHandler const* handler, std::string_view args) noexcept
235 {
236 ChatCommandResult next = args;
237 for (T& t : val)
238 if (!(next = ArgInfo<T>::TryConsume(t, handler, *next)))
239 break;
240 return next;
241 }
242 };
243
244 // variant
246 TC_GAME_API void PrefixVariantChatCommandError(ChatCommandResult& combined, ChatHandler const* handler) noexcept;
247
248 template <typename... Ts>
250 {
251 using Variant = std::variant<Ts...>;
252
253 template <std::size_t... I>
254 inline static bool TryConsume(ChatCommandResult& result, Variant& val, ChatHandler const* handler, std::string_view args, std::index_sequence<I...>) noexcept
255 {
256 return (HandleVariantChatCommandConsumeResults(result, ArgInfo<std::variant_alternative_t<I, Variant>>::TryConsume(val.template emplace<I>(), handler, args), handler) || ...);
257 }
258
259 static ChatCommandResult TryConsume(Trinity::ChatCommands::Variant<Ts...>& val, ChatHandler const* handler, std::string_view args) noexcept
260 {
261 ChatCommandResult result = std::nullopt;
262 if (!TryConsume(result, val, handler, args, std::index_sequence_for<Ts...>()))
263 PrefixVariantChatCommandError(result, handler);
264 return result;
265 }
266 };
267
268 // AchievementEntry* from numeric id or link
269 template <>
271 {
272 static ChatCommandResult TryConsume(AchievementEntry const*&, ChatHandler const*, std::string_view) noexcept;
273 };
274
275 // CurrencyTypesEntry* from numeric id or link
276 template <>
278 {
279 static ChatCommandResult TryConsume(CurrencyTypesEntry const*&, ChatHandler const*, std::string_view) noexcept;
280 };
281
282 // GameTele* from string name or link
283 template <>
285 {
286 static ChatCommandResult TryConsume(GameTele const*&, ChatHandler const*, std::string_view) noexcept;
287 };
288
289 // ItemTemplate* from numeric id or link
290 template <>
292 {
293 static ChatCommandResult TryConsume(ItemTemplate const*&, ChatHandler const*, std::string_view) noexcept;
294 };
295
296 // Quest* from numeric id or link
297 template <>
298 struct TC_GAME_API ArgInfo<Quest const*>
299 {
300 static ChatCommandResult TryConsume(Quest const*&, ChatHandler const*, std::string_view) noexcept;
301 };
302
303 // SpellInfo const* from spell id or link
304 template <>
306 {
307 static ChatCommandResult TryConsume(SpellInfo const*&, ChatHandler const*, std::string_view) noexcept;
308 };
309
310}
311
312#endif
#define TC_GAME_API
Definition Define.h:129
int64_t int64
Definition Define.h:149
@ LANG_CMDPARSER_INVALID_UTF8
Definition Language.h:1010
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:336
static EnumText ToString(Enum value)
Definition SmartEnum.h:54
std::conjunction< std::is_enum< T >, std::integral_constant< bool, IsEnumFlag(T{})> > IsFlag
Definition EnumFlag.h:31
TokenizeResult tokenize(std::string_view args) noexcept
TC_GAME_API bool HandleVariantChatCommandConsumeResults(ChatCommandResult &combined, ChatCommandResult &&current, ChatHandler const *handler) noexcept
TC_GAME_API char const * GetTrinityString(ChatHandler const *handler, TrinityStrings which)
TC_GAME_API void PrefixVariantChatCommandError(ChatCommandResult &combined, ChatHandler const *handler) noexcept
TC_GAME_API void InvalidStringValueFormatError(ChatCommandResult &result, ChatHandler const *handler, std::string_view arg, std::type_info const &type) noexcept
STL namespace.
static ChatCommandResult TryConsume(AchievementEntry const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(CurrencyTypesEntry const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(GameTele const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(ItemTemplate const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(Quest const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(SpellInfo const *&, ChatHandler const *, std::string_view) noexcept
static ChatCommandResult TryConsume(T &tag, ChatHandler const *handler, std::string_view args) noexcept
static ChatCommandResult TryConsume(T &val, ChatHandler const *handler, std::string_view args) noexcept
static SearchMap MakeSearchMap() noexcept
static ChatCommandResult TryConsume(Trinity::ChatCommands::Variant< Ts... > &val, ChatHandler const *handler, std::string_view args) noexcept
static bool TryConsume(ChatCommandResult &result, Variant &val, ChatHandler const *handler, std::string_view args, std::index_sequence< I... >) noexcept
static ChatCommandResult TryConsume(std::array< T, N > &val, ChatHandler const *handler, std::string_view args) noexcept
static ChatCommandResult TryConsume(std::string &val, ChatHandler const *handler, std::string_view args) noexcept
static ChatCommandResult TryConsume(std::string_view &val, ChatHandler const *, std::string_view args) noexcept
static ChatCommandResult TryConsume(std::vector< T > &val, ChatHandler const *handler, std::string_view args) noexcept
static ChatCommandResult TryConsume(std::wstring &val, ChatHandler const *handler, std::string_view args) noexcept
static void AddSearchMapEntry(SearchMap &map, int64 val, EnumText const &text) noexcept
std::vector< std::pair< std::string_view, Optional< int64 > > > SearchMap