From 861fb8dd94f583ee76782388dd31e9ea5cce0190 Mon Sep 17 00:00:00 2001 From: Mathieu Cayeux Date: Sun, 11 Feb 2024 21:10:35 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9A=20Improved=20chat=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/chatmessage.cpp | 125 ++++++++++++++++++++++++++++++++----- src/types/chatmessage.h | 126 +++++++++++++++++++++++++++++++++++++- src/utils/config.cpp | 2 +- 3 files changed, 236 insertions(+), 17 deletions(-) diff --git a/src/types/chatmessage.cpp b/src/types/chatmessage.cpp index 75a43cbf..3134822f 100644 --- a/src/types/chatmessage.cpp +++ b/src/types/chatmessage.cpp @@ -79,6 +79,8 @@ void ChatMessage::load(const rapidjson::Value &document) LS(insertion); LS(text); + clickEvent.load(document); + if ((it = document.FindMember("extra")) != document.MemberEnd() && it->value.IsArray()) { @@ -104,6 +106,7 @@ void ChatMessage::save(rapidjson::Value &document, rapidjson::Document::Allocato WV(underlined); WV(strikethrough); WV(obfuscated); +#undef WV #define WS(x) \ if (x.size() != 0) \ @@ -113,6 +116,10 @@ void ChatMessage::save(rapidjson::Value &document, rapidjson::Document::Allocato WS(insertion); WS(text); +#undef WS + + clickEvent.save(document, alloc); + if (next == nullptr) return; ChatMessage *n = next; @@ -137,19 +144,107 @@ bool operator==(const ChatMessage &lhs, const ChatMessage &rhs) void ChatMessage::loadLua(lua_State *state, const char *namespaceName) { luabridge::getGlobalNamespace(state) - .beginNamespace(namespaceName) - .beginClass("ChatMessage") - .addConstructor([](void* ptr) {return new (ptr) ChatMessage();}, - [](void* ptr, const std::string &msg) {return new (ptr) ChatMessage(msg);}) - .addProperty("bold", &ChatMessage::bold) - .addProperty("italic", &ChatMessage::italic) - .addProperty("underlined", &ChatMessage::underlined) - .addProperty("strikethrough", &ChatMessage::strikethrough) - .addProperty("obfuscated", &ChatMessage::obfuscated) - .addProperty("color", &ChatMessage::color) - .addProperty("insertion", &ChatMessage::insertion) - .addProperty("text", &ChatMessage::text) - .addFunction("addExtra", &ChatMessage::addExtra) - .endClass() - .endNamespace(); + .beginNamespace(namespaceName) + .beginClass("ChatMessage") + .addConstructor([](void *ptr) + { return new (ptr) ChatMessage(); }, + [](void *ptr, const std::string &msg) + { return new (ptr) ChatMessage(msg); }) + .addProperty("bold", &ChatMessage::bold) + .addProperty("italic", &ChatMessage::italic) + .addProperty("underlined", &ChatMessage::underlined) + .addProperty("strikethrough", &ChatMessage::strikethrough) + .addProperty("obfuscated", &ChatMessage::obfuscated) + .addProperty("color", &ChatMessage::color) + .addProperty("insertion", &ChatMessage::insertion) + .addProperty("text", &ChatMessage::text) + .addFunction("addExtra", &ChatMessage::addExtra) + .addProperty("clickEvent", &ChatMessage::clickEvent) + .endClass() + .endNamespace(); + + ClickEvent::loadLua(state, namespaceName); +} + +ChatMessage::ClickEvent::ClickEvent(ActionType action, const std::string &value) + : action(action), value(value) +{ +} + +ChatMessage::ClickEvent::ClickEvent(uint changePage) + : action(ActionType::CHANGE_PAGE), value(std::to_string(changePage)) +{ +} + +ChatMessage::ClickEvent::ClickEvent() : action(ActionType::NONE) +{ +} + +const std::unordered_map ACTION_TABLE{ + {"open_url", ChatMessage::ClickEvent::OPEN_URL}, + {"run_command", ChatMessage::ClickEvent::RUN_COMMAND}, + {"suggest_command", ChatMessage::ClickEvent::SUGGEST_COMMAND}, + {"change_page", ChatMessage::ClickEvent::CHANGE_PAGE}, + {"copy_to_clipboard", ChatMessage::ClickEvent::COPY_TO_CLIPBOARD}, +}; + +void ChatMessage::ClickEvent::load(const rapidjson::Value &document) +{ + rapidjson::Document::ConstMemberIterator it; + if ((it = document.FindMember("clickEvent")) == document.MemberEnd() || + !it->value.IsObject()) + return; + const rapidjson::Value &clickEvent = it->value; + + if ((it = clickEvent.FindMember("action")) == document.MemberEnd() || + !it->value.IsString()) + return; + std::string stringAction(it->value.GetString(), it->value.GetStringLength()); + + if ((it = clickEvent.FindMember("value")) == document.MemberEnd() || + !it->value.IsString()) + return; + value = std::string(it->value.GetString(), it->value.GetStringLength()); + + if (!ACTION_TABLE.contains(stringAction)) + { + action = ActionType::NONE; + value = ""; + return; + } + + action = ACTION_TABLE.at(stringAction); +} + +void ChatMessage::ClickEvent::save(rapidjson::Value &document, rapidjson::Document::AllocatorType &alloc) const +{ + if (action == ActionType::NONE) + return; + + rapidjson::Value clickEvent(rapidjson::kObjectType); + auto it = std::find_if(std::begin(ACTION_TABLE), std::end(ACTION_TABLE), + [this](auto &&p) + { return std::get<1>(p) == action; }); + if (it == std::end(ACTION_TABLE)) + throw std::runtime_error("Could not parse action !"); + + std::string stringAction = it->first; + + clickEvent.AddMember("action", rapidjson::Value(stringAction.c_str(), stringAction.length(), alloc), alloc); + clickEvent.AddMember("value", rapidjson::Value(value.c_str(), value.length(), alloc), alloc); + + document.AddMember("clickEvent", clickEvent, alloc); +} + +void ChatMessage::ClickEvent::loadLua(lua_State *state, const char *namespaceName) +{ + luabridge::getGlobalNamespace(state) + .beginNamespace(namespaceName) + .beginNamespace("ChatMessage") + .beginClass("ClickEvent") + .addProperty("action", &ClickEvent::action) + .addProperty("value", &ClickEvent::value) + .endClass() + .endNamespace() + .endNamespace(); } diff --git a/src/types/chatmessage.h b/src/types/chatmessage.h index 49c0bfdc..a8c74053 100644 --- a/src/types/chatmessage.h +++ b/src/types/chatmessage.h @@ -13,6 +13,7 @@ #define MINESERVER_CHATMESSAGE_H #include +#include #include #include #include @@ -72,13 +73,124 @@ class ChatMessage std::string insertion{}; /** - * @brief The (limited) text + * @brief The text excluding extras * * Does not parse for additional string components, * only text. */ std::string text{}; + /** + * @brief Click Event + * + * On message click event + */ + class ClickEvent + { + public: + /** + * @brief Type of action to perform + * + */ + enum ActionType + { + /** + * @brief No action + * + * Click event will not be saved to JSON. + */ + NONE, + /** + * @brief Open URL + * + */ + OPEN_URL, + /** + * @brief Run command + * + */ + RUN_COMMAND, + /** + * @brief Suggest command to user + * + */ + SUGGEST_COMMAND, + /** + * @brief Change page (book only) + * + */ + CHANGE_PAGE, + /** + * @brief Copy text to clipboard + * + */ + COPY_TO_CLIPBOARD + }; + + /** + * @brief Action to perform + * + */ + ActionType action; + /** + * @brief Value of action + * + */ + std::string value; + + /** + * @brief Construct a new Click Event object + * + * @param action the action type + * @param value the value of action + */ + ClickEvent(ActionType action, const std::string &value); + /** + * @brief Construct a new Click Event object + * + * @param changePage see ActionType::CHANGE_PAGE + */ + ClickEvent(uint changePage); + /** + * @brief Construct a new Click Event object + * + */ + ClickEvent(); + /** + * @brief Destroy the Click Event object + * + */ + ~ClickEvent() = default; + + /** + * @brief Load click event from JSON + * + * @param document the document to load from + */ + void load(const rapidjson::Value &document); + /** + * @brief Save click event to JSON + * + * @param document the document to save to + * @param alloc the document allocator + */ + void save(rapidjson::Value &document, rapidjson::Document::AllocatorType &alloc) const; + + /** + * @brief Loads Click Event to lua + * + * @param state the state of lua + * @param namespaceName the namespace name + */ + static void loadLua(lua_State *state, const char *namespaceName); + }; + + /** + * @brief Click event for message + * + */ + ClickEvent clickEvent; + private: ChatMessage *next = nullptr; @@ -148,4 +260,16 @@ class ChatMessage static void loadLua(lua_State *state, const char *namespaceName); }; +template <> +struct luabridge::Stack + : luabridge::Enum +{ +}; + #endif // MINESERVER_CHATMESSAGE_H \ No newline at end of file diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 812bbcf5..7d39724c 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -90,7 +90,7 @@ void Field::load(const rapidjson::Document &document) if (loc == document.MemberEnd()) return; - if (!loc->value.IsInt()) + if (!loc->value.IsObject()) return; value = ChatMessage();