diff options
author | Peter Keresztes Schmidt <carbenium@outlook.com> | 2020-08-16 14:11:21 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-01-26 22:13:06 +0100 |
commit | 3923650aeb75611023aa1d46a4328838c8e0a33c (patch) | |
tree | afdf0c696ea88c3172528fc6f7966a351d07cf69 | |
parent | 2e3c612c808bca7601b32ce5dca28b204e652773 (diff) |
Core/ChatCommands: Add support for enum type arguments (PR #25242)
(cherry picked from commit 5e40eb20e2789b86d4786d86b4bbb8ae83de5e1e)
-rw-r--r-- | src/common/Utilities/Util.cpp | 19 | ||||
-rw-r--r-- | src/common/Utilities/Util.h | 3 | ||||
-rw-r--r-- | src/server/game/Chat/ChatCommands/ChatCommandArgs.h | 79 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_npc.cpp | 15 |
4 files changed, 105 insertions, 11 deletions
diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 42f87c36991..42064cc3466 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -652,6 +652,11 @@ void wstrToUpper(std::wstring& str) std::transform(str.begin(), str.end(), str.begin(), wcharToUpper); } +void strToLower(std::string& str) +{ + std::transform(str.begin(), str.end(), str.begin(), [](char c) { return std::tolower(c); }); +} + void wstrToLower(std::wstring& str) { std::transform(str.begin(), str.end(), str.begin(), wcharToLower); @@ -848,6 +853,20 @@ bool StringToBool(std::string const& str) return lowerStr == "1" || lowerStr == "true" || lowerStr == "yes"; } +bool StringEqualI(std::string const& str1, std::string const& str2) +{ + return std::equal(str1.begin(), str1.end(), str2.begin(), str2.end(), + [](char a, char b) + { + return std::tolower(a) == std::tolower(b); + }); +} + +bool StringStartsWith(std::string const& haystack, std::string const& needle) +{ + return (haystack.rfind(needle, 0) == 0); +} + bool StringContainsStringI(std::string const& haystack, std::string const& needle) { return haystack.end() != diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index a7f6619838a..d048f3437aa 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -324,6 +324,7 @@ inline bool isUpper(wchar_t wchar) TC_COMMON_API std::wstring wstrCaseAccentInsensitiveParse(std::wstring const& wstr, LocaleConstant locale); TC_COMMON_API void wstrToUpper(std::wstring& str); +TC_COMMON_API void strToLower(std::string& str); TC_COMMON_API void wstrToLower(std::wstring& str); TC_COMMON_API std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension); @@ -377,6 +378,8 @@ inline std::vector<uint8> HexStrToByteVector(std::string const& str, bool revers TC_COMMON_API bool StringToBool(std::string const& str); TC_COMMON_API float DegToRad(float degrees); +TC_COMMON_API bool StringEqualI(std::string const& str1, std::string const& str2); +TC_COMMON_API bool StringStartsWith(std::string const& haystack, std::string const& needle); TC_COMMON_API bool StringContainsStringI(std::string const& haystack, std::string const& needle); template <typename T> inline bool ValueContainsStringI(std::pair<T, std::string> const& haystack, std::string const& needle) diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h index a2ebccf03bb..6b5121c5044 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h @@ -20,6 +20,9 @@ #include "ChatCommandHelpers.h" #include "ChatCommandTags.h" +#include "SmartEnum.h" +#include "Util.h" +#include <map> struct GameTele; @@ -99,6 +102,82 @@ struct ArgInfo<std::string, void> } }; +// enum +template <typename T> +struct ArgInfo<T, std::enable_if_t<std::is_enum_v<T>>> +{ + static std::map<std::string, Optional<T>> MakeSearchMap() + { + std::map<std::string, Optional<T>> map; + for (T val : EnumUtils::Iterate<T>()) + { + EnumText text = EnumUtils::ToString(val); + + std::string title(text.Title); + strToLower(title); + std::string constant(text.Constant); + strToLower(constant); + + auto [constantIt, constantNew] = map.try_emplace(constant, val); + if (!constantNew) + constantIt->second = std::nullopt; + + if (title != constant) + { + auto [titleIt, titleNew] = map.try_emplace(title, val); + if (!titleNew) + titleIt->second = std::nullopt; + } + } + return map; + } + + static inline std::map<std::string, Optional<T>> const SearchMap = MakeSearchMap(); + + static T const* Match(std::string s) + { + strToLower(s); + + auto it = SearchMap.lower_bound(s); + if (it == SearchMap.end() || !StringStartsWith(it->first, s)) // not a match + return nullptr; + + auto it2 = it; + ++it2; + if (it2 != SearchMap.end() && StringStartsWith(it2->first, s)) // not unique + return nullptr; + + if (it->second) + return &*it->second; + else + return nullptr; + } + + static char const* TryConsume(T& val, char const* args) + { + std::string strVal; + char const* ret = ArgInfo<std::string>::TryConsume(strVal, args); + + if (!ret) + return nullptr; + + if (T const* tmpVal = Match(strVal)) + { + val = *tmpVal; + return ret; + } + + // Value not found. Try to parse arg as underlying type and cast it to enum type + using U = std::underlying_type_t<T>; + U uVal = 0; + ret = ArgInfo<U>::TryConsume(uVal, args); + if (ret) + val = static_cast<T>(uVal); + + return ret; + } +}; + // a container tag template <typename T> struct ArgInfo<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>> diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index fd77e4dbea9..d30d77f4f39 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -549,13 +549,8 @@ public: } //set npcflag of creature - static bool HandleNpcSetFlagCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetFlagCommand(ChatHandler* handler, NPCFlags npcFlags, NPCFlags2 npcFlags2) { - if (!*args) - return false; - - uint64 npcFlags = atoull(args); - Creature* creature = handler->getSelectedCreature(); if (!creature) @@ -565,14 +560,12 @@ public: return false; } - uint32 raw[2]; - memcpy(raw, &npcFlags, sizeof(raw)); - creature->SetNpcFlags(NPCFlags(raw[0])); - creature->SetNpcFlags2(NPCFlags2(raw[1])); + creature->SetNpcFlags(npcFlags); + creature->SetNpcFlags2(npcFlags2); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG); - stmt->setUInt64(0, npcFlags); + stmt->setUInt64(0, uint64(npcFlags) | (uint64(npcFlags2) << 32)); stmt->setUInt32(1, creature->GetEntry()); WorldDatabase.Execute(stmt); |