aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Keresztes Schmidt <carbenium@outlook.com>2020-08-16 14:11:21 +0200
committerShauren <shauren.trinity@gmail.com>2022-01-26 22:13:06 +0100
commit3923650aeb75611023aa1d46a4328838c8e0a33c (patch)
treeafdf0c696ea88c3172528fc6f7966a351d07cf69
parent2e3c612c808bca7601b32ce5dca28b204e652773 (diff)
Core/ChatCommands: Add support for enum type arguments (PR #25242)
(cherry picked from commit 5e40eb20e2789b86d4786d86b4bbb8ae83de5e1e)
-rw-r--r--src/common/Utilities/Util.cpp19
-rw-r--r--src/common/Utilities/Util.h3
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandArgs.h79
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp15
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);