From 6d9771bc329e987d5511134f63c738741b1f8f1e Mon Sep 17 00:00:00 2001 From: GHOST11111100 Date: Wed, 15 Jan 2025 18:42:16 +0300 Subject: [PATCH 01/36] added base hex color parser, and md statement --- src/graphics/ui/markdown.cpp | 77 ++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/src/graphics/ui/markdown.cpp b/src/graphics/ui/markdown.cpp index ab328e66..dd8613b5 100644 --- a/src/graphics/ui/markdown.cpp +++ b/src/graphics/ui/markdown.cpp @@ -1,15 +1,21 @@ #include "markdown.hpp" - #include "graphics/core/Font.hpp" using namespace markdown; +static inline int hexchar2int(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + template static inline void emit( CharT c, FontStylesScheme& styles, std::basic_stringstream& ss ) { ss << c; - styles.map.emplace_back(styles.palette.size()-1); + styles.map.emplace_back(styles.palette.size() - 1); } template @@ -21,21 +27,36 @@ static inline void emit_md( } template -static inline void restyle( - CharT c, - FontStyle& style, - FontStylesScheme& styles, - std::basic_stringstream& ss, - int& pos, - bool eraseMarkdown -) { - styles.palette.push_back(style); - if (!eraseMarkdown) { - emit_md(c, styles, ss); +static glm::vec4 parse_color(const std::basic_string_view& color_code) { + if (color_code.size() != 9 || color_code[0] != '#') { + return glm::vec4(1, 1, 1, 1); // default to white } - pos++; + + auto hex_to_float = [](char high, char low) { + int high_val = hexchar2int(high); + int low_val = hexchar2int(low); + if (high_val == -1 || low_val == -1) { + return 1.0f; // default to max value on error + } + return (high_val * 16 + low_val) / 255.0f; + }; + + return glm::vec4( + hex_to_float(color_code[1], color_code[2]), + hex_to_float(color_code[3], color_code[4]), + hex_to_float(color_code[5], color_code[6]), + hex_to_float(color_code[7], color_code[8]) + ); } +template +static inline void apply_color(const std::basic_string_view& color_code, FontStylesScheme& styles) { + FontStyle style = styles.palette.back(); + style.color = parse_color(color_code); + styles.palette.push_back(style); +} + +// TODO: Refactor md code processing template Result process_markdown( std::basic_string_view source, bool eraseMarkdown @@ -50,6 +71,19 @@ Result process_markdown( int pos = 0; while (pos < source.size()) { CharT first = source[pos]; + + if (first == '[' && pos + 10 < source.size() && source[pos + 1] == '#' && source[pos + 9] == ']') { + std::basic_string_view color_code = source.substr(pos + 1, 9); + apply_color(color_code, styles); + if (!eraseMarkdown) { + for (int i = 0; i < 10; ++i) { + emit_md(source[pos + i], styles, ss); + } + } + pos += 10; // Skip past the color code + continue; + } + if (first == '\\') { if (pos + 1 < source.size()) { CharT second = source[++pos]; @@ -67,32 +101,33 @@ Result process_markdown( pos--; } } else if (first == '*') { - if (pos + 1 < source.size() && source[pos+1] == '*') { + if (pos + 1 < source.size() && source[pos + 1] == '*') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.bold = !style.bold; - restyle(first, style, styles, ss, pos, eraseMarkdown); + styles.palette.push_back(style); continue; } style.italic = !style.italic; - restyle(first, style, styles, ss, pos, eraseMarkdown); + styles.palette.push_back(style); continue; - } else if (first == '_' && pos + 1 < source.size() && source[pos+1] == '_') { + } else if (first == '_' && pos + 1 < source.size() && source[pos + 1] == '_') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.underline = !style.underline; - restyle(first, style, styles, ss, pos, eraseMarkdown); + styles.palette.push_back(style); continue; - } else if (first == '~' && pos + 1 < source.size() && source[pos+1] == '~') { + } else if (first == '~' && pos + 1 < source.size() && source[pos + 1] == '~') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.strikethrough = !style.strikethrough; - restyle(first, style, styles, ss, pos, eraseMarkdown); + styles.palette.push_back(style); continue; } + if (first == '\n') { styles.palette.push_back(styles.palette.at(1)); } From 9ce34080f775b3c05afe83c1d814aa83be4a274c Mon Sep 17 00:00:00 2001 From: GHOST11111100 Date: Wed, 15 Jan 2025 19:07:48 +0300 Subject: [PATCH 02/36] fixed engine hang when using other special characters --- src/graphics/ui/markdown.cpp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/graphics/ui/markdown.cpp b/src/graphics/ui/markdown.cpp index dd8613b5..8a1b13bf 100644 --- a/src/graphics/ui/markdown.cpp +++ b/src/graphics/ui/markdown.cpp @@ -56,7 +56,22 @@ static inline void apply_color(const std::basic_string_view& color_code, styles.palette.push_back(style); } -// TODO: Refactor md code processing +template +static inline void restyle( + CharT c, + FontStyle& style, + FontStylesScheme& styles, + std::basic_stringstream& ss, + int& pos, + bool eraseMarkdown +) { + styles.palette.push_back(style); + if (!eraseMarkdown) { + emit_md(c, styles, ss); + } + pos++; +} + template Result process_markdown( std::basic_string_view source, bool eraseMarkdown @@ -101,33 +116,32 @@ Result process_markdown( pos--; } } else if (first == '*') { - if (pos + 1 < source.size() && source[pos + 1] == '*') { + if (pos + 1 < source.size() && source[pos+1] == '*') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.bold = !style.bold; - styles.palette.push_back(style); + restyle(first, style, styles, ss, pos, eraseMarkdown); continue; } style.italic = !style.italic; - styles.palette.push_back(style); + restyle(first, style, styles, ss, pos, eraseMarkdown); continue; - } else if (first == '_' && pos + 1 < source.size() && source[pos + 1] == '_') { + } else if (first == '_' && pos + 1 < source.size() && source[pos+1] == '_') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.underline = !style.underline; - styles.palette.push_back(style); + restyle(first, style, styles, ss, pos, eraseMarkdown); continue; - } else if (first == '~' && pos + 1 < source.size() && source[pos + 1] == '~') { + } else if (first == '~' && pos + 1 < source.size() && source[pos+1] == '~') { pos++; if (!eraseMarkdown) emit_md(first, styles, ss); style.strikethrough = !style.strikethrough; - styles.palette.push_back(style); + restyle(first, style, styles, ss, pos, eraseMarkdown); continue; } - if (first == '\n') { styles.palette.push_back(styles.palette.at(1)); } From 6ca8dc18cf9a2b062fdc7a4e0a19f4e4f16b5ec8 Mon Sep 17 00:00:00 2001 From: GHOST11111100 Date: Wed, 15 Jan 2025 20:09:30 +0300 Subject: [PATCH 03/36] fix hex code length and use a exists hex to int method; added docs for color codes --- doc/en/text-styles.md | 31 +++++++++++++++++++++++++++++++ doc/ru/text-styles.md | 30 ++++++++++++++++++++++++++++++ src/graphics/ui/markdown.cpp | 20 +++++++------------- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/doc/en/text-styles.md b/doc/en/text-styles.md index e85437e1..4afce42a 100644 --- a/doc/en/text-styles.md +++ b/doc/en/text-styles.md @@ -19,3 +19,34 @@ Styles can be combined. Example: Output: ***Message*** using *~~combed~~ combined* styles~~.~~ + +# Colors + +Text color can be set using a color code: [#RRGGBB] + + +| Component | Purpose | +| --------- | --------------------------------- | +| R | Represents the intensity of red | +| G | Represents the intensity of green | +| B | Represents the intensity of blue | + +### Example: + + + + [#ff0000] + Red Text + + + + + [#00ff00] + Green Text + + + + + [#0000ff] + Blue Text + diff --git a/doc/ru/text-styles.md b/doc/ru/text-styles.md index 0a09abe3..4fbe3ed5 100644 --- a/doc/ru/text-styles.md +++ b/doc/ru/text-styles.md @@ -19,3 +19,33 @@ Вывод: ***Сообщение***, демонстрирующее *~~обедненные~~ объединенные* стили~~.~~ + +## Цвета + +Цвет текста задается при помощи цветового кода: [#RRGGBB] + +| Компонент | Назначение | +| ------------ | ------------------------- | +| R | Используется для интенсивности красного | +| G | Используется для интенсивности зеленого | +| B | Используется для интенсивности синего | + +### Например: + + + + [#ff0000] + Красный Текст + + + + + [#00ff00] + Зеленый Текст + + + + + [#0000ff] + Синий Текст + \ No newline at end of file diff --git a/src/graphics/ui/markdown.cpp b/src/graphics/ui/markdown.cpp index 8a1b13bf..bbbc298a 100644 --- a/src/graphics/ui/markdown.cpp +++ b/src/graphics/ui/markdown.cpp @@ -1,15 +1,9 @@ #include "markdown.hpp" +#include "coders/commons.hpp" #include "graphics/core/Font.hpp" using namespace markdown; -static inline int hexchar2int(char c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - return -1; -} - template static inline void emit( CharT c, FontStylesScheme& styles, std::basic_stringstream& ss @@ -28,7 +22,7 @@ static inline void emit_md( template static glm::vec4 parse_color(const std::basic_string_view& color_code) { - if (color_code.size() != 9 || color_code[0] != '#') { + if (color_code.size() != 8 || color_code[0] != '#') { return glm::vec4(1, 1, 1, 1); // default to white } @@ -45,7 +39,7 @@ static glm::vec4 parse_color(const std::basic_string_view& color_code) { hex_to_float(color_code[1], color_code[2]), hex_to_float(color_code[3], color_code[4]), hex_to_float(color_code[5], color_code[6]), - hex_to_float(color_code[7], color_code[8]) + 1 ); } @@ -87,15 +81,15 @@ Result process_markdown( while (pos < source.size()) { CharT first = source[pos]; - if (first == '[' && pos + 10 < source.size() && source[pos + 1] == '#' && source[pos + 9] == ']') { - std::basic_string_view color_code = source.substr(pos + 1, 9); + if (first == '[' && pos + 9 < source.size() && source[pos + 1] == '#' && source[pos + 8] == ']') { + std::basic_string_view color_code = source.substr(pos + 1, 8); apply_color(color_code, styles); if (!eraseMarkdown) { - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 9; ++i) { emit_md(source[pos + i], styles, ss); } } - pos += 10; // Skip past the color code + pos += 9; // Skip past the color code continue; } From a93af583d19b9fd640ef287b90fabd0eaa7d0fe4 Mon Sep 17 00:00:00 2001 From: GHOST11111100 Date: Wed, 15 Jan 2025 21:22:13 +0300 Subject: [PATCH 04/36] added color code escaping --- src/graphics/ui/markdown.cpp | 70 ++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/graphics/ui/markdown.cpp b/src/graphics/ui/markdown.cpp index bbbc298a..8616facd 100644 --- a/src/graphics/ui/markdown.cpp +++ b/src/graphics/ui/markdown.cpp @@ -1,4 +1,5 @@ #include "markdown.hpp" + #include "coders/commons.hpp" #include "graphics/core/Font.hpp" @@ -23,14 +24,14 @@ static inline void emit_md( template static glm::vec4 parse_color(const std::basic_string_view& color_code) { if (color_code.size() != 8 || color_code[0] != '#') { - return glm::vec4(1, 1, 1, 1); // default to white + return glm::vec4(1, 1, 1, 1); // default to white } auto hex_to_float = [](char high, char low) { int high_val = hexchar2int(high); int low_val = hexchar2int(low); if (high_val == -1 || low_val == -1) { - return 1.0f; // default to max value on error + return 1.0f; // default to max value on error } return (high_val * 16 + low_val) / 255.0f; }; @@ -44,7 +45,9 @@ static glm::vec4 parse_color(const std::basic_string_view& color_code) { } template -static inline void apply_color(const std::basic_string_view& color_code, FontStylesScheme& styles) { +static inline void apply_color( + const std::basic_string_view& color_code, FontStylesScheme& styles +) { FontStyle style = styles.palette.back(); style.color = parse_color(color_code); styles.palette.push_back(style); @@ -73,7 +76,7 @@ Result process_markdown( std::basic_stringstream ss; FontStylesScheme styles { // markdown default - {{false, false, false, false, glm::vec4(1,1,1,0.5f)}, {}}, + {{false, false, false, false, glm::vec4(1, 1, 1, 0.5f)}, {}}, {} }; FontStyle style; @@ -81,18 +84,6 @@ Result process_markdown( while (pos < source.size()) { CharT first = source[pos]; - if (first == '[' && pos + 9 < source.size() && source[pos + 1] == '#' && source[pos + 8] == ']') { - std::basic_string_view color_code = source.substr(pos + 1, 8); - apply_color(color_code, styles); - if (!eraseMarkdown) { - for (int i = 0; i < 9; ++i) { - emit_md(source[pos + i], styles, ss); - } - } - pos += 9; // Skip past the color code - continue; - } - if (first == '\\') { if (pos + 1 < source.size()) { CharT second = source[++pos]; @@ -106,14 +97,39 @@ Result process_markdown( emit(second, styles, ss); pos++; continue; + case '[': + if (pos + 9 < source.size() && source[pos + 1] == '#' && + source[pos + 8] == ']') { + if (!eraseMarkdown) { + emit_md(source[pos - 1], styles, ss); + } + for (int i = 0; i < 10; ++i) { + + emit(source[pos + i], styles, ss); + } + + pos += 10; + continue; + } } pos--; } + } else if (first == '[' && pos + 9 < source.size() && + source[pos + 1] == '#' && source[pos + 8] == ']') { + std::basic_string_view color_code = + source.substr(pos + 1, 8); + apply_color(color_code, styles); + if (!eraseMarkdown) { + for (int i = 0; i < 9; ++i) { + emit_md(source[pos + i], styles, ss); + } + } + pos += 9; // Skip past the color code + continue; } else if (first == '*') { - if (pos + 1 < source.size() && source[pos+1] == '*') { + if (pos + 1 < source.size() && source[pos + 1] == '*') { pos++; - if (!eraseMarkdown) - emit_md(first, styles, ss); + if (!eraseMarkdown) emit_md(first, styles, ss); style.bold = !style.bold; restyle(first, style, styles, ss, pos, eraseMarkdown); continue; @@ -121,17 +137,17 @@ Result process_markdown( style.italic = !style.italic; restyle(first, style, styles, ss, pos, eraseMarkdown); continue; - } else if (first == '_' && pos + 1 < source.size() && source[pos+1] == '_') { + } else if (first == '_' && pos + 1 < source.size() && + source[pos + 1] == '_') { pos++; - if (!eraseMarkdown) - emit_md(first, styles, ss); + if (!eraseMarkdown) emit_md(first, styles, ss); style.underline = !style.underline; restyle(first, style, styles, ss, pos, eraseMarkdown); continue; - } else if (first == '~' && pos + 1 < source.size() && source[pos+1] == '~') { + } else if (first == '~' && pos + 1 < source.size() && + source[pos + 1] == '~') { pos++; - if (!eraseMarkdown) - emit_md(first, styles, ss); + if (!eraseMarkdown) emit_md(first, styles, ss); style.strikethrough = !style.strikethrough; restyle(first, style, styles, ss, pos, eraseMarkdown); continue; @@ -149,6 +165,8 @@ Result markdown::process(std::string_view source, bool eraseMarkdown) { return process_markdown(source, eraseMarkdown); } -Result markdown::process(std::wstring_view source, bool eraseMarkdown) { +Result markdown::process( + std::wstring_view source, bool eraseMarkdown +) { return process_markdown(source, eraseMarkdown); } From acb07c6664fb656ef6c0f9e0ce345f9560b6f656 Mon Sep 17 00:00:00 2001 From: GHOST11111100 Date: Wed, 15 Jan 2025 21:28:52 +0300 Subject: [PATCH 05/36] fixed color code highlight --- src/graphics/ui/markdown.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/graphics/ui/markdown.cpp b/src/graphics/ui/markdown.cpp index 8616facd..44991804 100644 --- a/src/graphics/ui/markdown.cpp +++ b/src/graphics/ui/markdown.cpp @@ -114,10 +114,8 @@ Result process_markdown( } pos--; } - } else if (first == '[' && pos + 9 < source.size() && - source[pos + 1] == '#' && source[pos + 8] == ']') { - std::basic_string_view color_code = - source.substr(pos + 1, 8); + } else if (first == '[' && pos + 9 <= source.size() && source[pos + 1] == '#' && source[pos + 8] == ']') { + std::basic_string_view color_code = source.substr(pos + 1, 8); apply_color(color_code, styles); if (!eraseMarkdown) { for (int i = 0; i < 9; ++i) { From 43f0cbe3fe5f8231af0415207fda129e5e58b81f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 15 Jan 2025 22:25:51 +0300 Subject: [PATCH 06/36] add player.is_suspended, player.set_suspended --- src/logic/LevelController.cpp | 6 ++++++ src/logic/scripting/lua/libs/libplayer.cpp | 16 ++++++++++++++++ src/objects/Player.cpp | 8 ++++++++ src/objects/Player.hpp | 4 ++++ src/objects/Players.cpp | 21 +++++++++++++++++++++ src/objects/Players.hpp | 4 ++++ 6 files changed, 59 insertions(+) diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 47a6384d..422807c6 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -66,6 +66,9 @@ LevelController::LevelController( void LevelController::update(float delta, bool pause) { for (const auto& [_, player] : *level->players) { + if (player->isSuspended()) { + continue; + } glm::vec3 position = player->getPosition(); player->chunks->configure( position.x, @@ -85,6 +88,9 @@ void LevelController::update(float delta, bool pause) { level->entities->updatePhysics(delta); level->entities->update(delta); for (const auto& [_, player] : *level->players) { + if (player->isSuspended()) { + continue; + } if (playerTickClock.update(delta)) { if (player->getId() % playerTickClock.getParts() == playerTickClock.getPart()) { diff --git a/src/logic/scripting/lua/libs/libplayer.cpp b/src/logic/scripting/lua/libs/libplayer.cpp index af908aea..5979d0f6 100644 --- a/src/logic/scripting/lua/libs/libplayer.cpp +++ b/src/logic/scripting/lua/libs/libplayer.cpp @@ -284,6 +284,20 @@ static int l_delete(lua::State* L) { return 0; } +static int l_is_suspended(lua::State* L) { + if (auto player = get_player(L, 1)) { + return lua::pushboolean(L, player->isSuspended()); + } + return 0; +} + +static int l_set_suspended(lua::State* L) { + if (auto player = get_player(L, 1)) { + player->setSuspended(lua::toboolean(L, 2)); + } + return 0; +} + const luaL_Reg playerlib[] = { {"get_pos", lua::wrap}, {"set_pos", lua::wrap}, @@ -293,6 +307,8 @@ const luaL_Reg playerlib[] = { {"set_rot", lua::wrap}, {"get_dir", lua::wrap}, {"get_inventory", lua::wrap}, + {"is_suspended", lua::wrap}, + {"set_suspended", lua::wrap}, {"is_flight", lua::wrap}, {"set_flight", lua::wrap}, {"is_noclip", lua::wrap}, diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index f80fffa7..e0a4a49e 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -224,6 +224,14 @@ float Player::getSpeed() const { return speed; } +bool Player::isSuspended() const { + return suspended; +} + +void Player::setSuspended(bool flag) { + suspended = flag; +} + bool Player::isFlight() const { return flight; } diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index 1e87e2a7..8caf7a63 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -47,6 +47,7 @@ class Player : public Serializable { glm::vec3 position; glm::vec3 spawnpoint {}; std::shared_ptr inventory; + bool suspended = false; bool flight = false; bool noclip = false; bool infiniteItems = true; @@ -85,6 +86,9 @@ public: int getChosenSlot() const; float getSpeed() const; + bool isSuspended() const; + void setSuspended(bool flag); + bool isFlight() const; void setFlight(bool flag); diff --git a/src/objects/Players.cpp b/src/objects/Players.cpp index 1a683a34..edd74274 100644 --- a/src/objects/Players.cpp +++ b/src/objects/Players.cpp @@ -4,6 +4,7 @@ #include "items/Inventories.hpp" #include "world/Level.hpp" #include "world/World.hpp" +#include "objects/Entities.hpp" Players::Players(Level& level) : level(level) {} @@ -36,6 +37,26 @@ Player* Players::create() { return player; } +void Players::suspend(int64_t id) { + if (auto player = get(id)) { + if (player->isSuspended()) { + return; + } + player->setSuspended(true); + level.entities->despawn(player->getEntity()); + player->setEntity(0); + } +} + +void Players::resume(int64_t id) { + if (auto player = get(id)) { + if (!player->isSuspended()) { + return; + } + player->setSuspended(false); + } +} + void Players::remove(int64_t id) { players.erase(id); } diff --git a/src/objects/Players.hpp b/src/objects/Players.hpp index 74f5c565..74146ade 100644 --- a/src/objects/Players.hpp +++ b/src/objects/Players.hpp @@ -25,6 +25,10 @@ public: Player* create(); + void suspend(int64_t id); + + void resume(int64_t id); + void remove(int64_t id); dv::value serialize() const override; From b59752bc845c0d224ac8c376961e109ffd941a14 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 01:23:45 +0300 Subject: [PATCH 07/36] fix player_animator --- res/content/base/scripts/components/player_animator.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/content/base/scripts/components/player_animator.lua b/res/content/base/scripts/components/player_animator.lua index 871284d5..f85deddc 100644 --- a/res/content/base/scripts/components/player_animator.lua +++ b/res/content/base/scripts/components/player_animator.lua @@ -12,7 +12,7 @@ local function refresh_model(id) end function on_render() - local invid, slotid = player.get_inventory() + local invid, slotid = player.get_inventory(hud.get_player()) local id, _ = inventory.get(invid, slotid) if id ~= itemid then refresh_model(id) From 44b9e21d460217787a9f7379fbd1b0b318994c53 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 03:46:56 +0300 Subject: [PATCH 08/36] fix input.add_callback --- src/logic/scripting/lua/libs/libinput.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/logic/scripting/lua/libs/libinput.cpp b/src/logic/scripting/lua/libs/libinput.cpp index 3447728b..4121a384 100644 --- a/src/logic/scripting/lua/libs/libinput.cpp +++ b/src/logic/scripting/lua/libs/libinput.cpp @@ -45,11 +45,6 @@ static int l_add_callback(lua::State* L) { handler = Events::keyCallbacks[key].add(actual_callback); } } - - const auto& bind = Events::bindings.find(bindname); - if (bind == Events::bindings.end()) { - throw std::runtime_error("unknown binding " + util::quote(bindname)); - } auto callback = [=]() -> bool { if (!scripting::engine->getGUI()->isFocusCaught()) { return actual_callback(); @@ -57,6 +52,10 @@ static int l_add_callback(lua::State* L) { return false; }; if (handler == nullptr) { + const auto& bind = Events::bindings.find(bindname); + if (bind == Events::bindings.end()) { + throw std::runtime_error("unknown binding " + util::quote(bindname)); + } handler = bind->second.onactived.add(callback); } From 2073d3782ad40ebc7cddf27e73388bb0ce39c077 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 04:16:32 +0300 Subject: [PATCH 09/36] fix HandlersList concurrency --- src/util/HandlersList.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/util/HandlersList.hpp b/src/util/HandlersList.hpp index 737fdf36..45882512 100644 --- a/src/util/HandlersList.hpp +++ b/src/util/HandlersList.hpp @@ -14,7 +14,7 @@ namespace util { int nextid = 1; std::unordered_map> handlers; std::vector order; - std::recursive_mutex mutex; + std::mutex mutex; public: HandlersList() = default; @@ -46,11 +46,15 @@ namespace util { } void notify(Types...args) { - std::lock_guard lock(mutex); - - auto orderCopy = order; + std::vector orderCopy; + decltype(handlers) handlersCopy; + { + std::lock_guard lock(mutex); + orderCopy = order; + handlersCopy = handlers; + } for (auto it = orderCopy.rbegin(); it != orderCopy.rend(); ++it) { - if (handlers.at(*it)(args...)) { + if (handlersCopy.at(*it)(args...)) { break; } } From 8aee8d81fb639fbdea005f5227f2c9284e84418e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:55:49 +0300 Subject: [PATCH 10/36] fix: player name still visible after player removal --- src/graphics/render/Decorator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 4c9b9289..e9fda381 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -156,6 +156,7 @@ void Decorator::update(float delta, const Camera& camera) { auto note = renderer.texts->get(textsIter->second); auto player = level.players->get(textsIter->first); if (player == nullptr) { + renderer.texts->remove(textsIter->second); textsIter = playerTexts.erase(textsIter); } else { note->setPosition(player->getPosition() + glm::vec3(0, 1, 0)); From b5999fe36420d116674abc353ed3dad739ac5f70 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:57:01 +0300 Subject: [PATCH 11/36] fix some UB --- src/lighting/Lighting.cpp | 12 +++++++++++- src/logic/scripting/lua/lua_util.hpp | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index bf55e001..eb721db2 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -8,9 +8,12 @@ #include "voxels/Block.hpp" #include "constants.hpp" #include "util/timeutil.hpp" +#include "debug/Logger.hpp" #include +static debug::Logger logger("lighting"); + Lighting::Lighting(const Content& content, Chunks& chunks) : content(content), chunks(chunks) { auto& indices = *content.getIndices(); @@ -63,6 +66,10 @@ void Lighting::buildSkyLight(int cx, int cz){ const auto blockDefs = content.getIndices()->blocks.getDefs(); Chunk* chunk = chunks.getChunk(cx, cz); + if (chunk == nullptr) { + logger.error() << "attempted to build sky lights to chunk missing in local matrix"; + return; + } for (int z = 0; z < CHUNK_D; z++){ for (int x = 0; x < CHUNK_W; x++){ int gx = x + cx * CHUNK_W; @@ -95,7 +102,10 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { auto blockDefs = content.getIndices()->blocks.getDefs(); auto chunk = chunks.getChunk(cx, cz); - + if (chunk == nullptr) { + logger.error() << "attempted to build lights to chunk missing in local matrix"; + return; + } for (uint y = 0; y < CHUNK_H; y++){ for (uint z = 0; z < CHUNK_D; z++){ for (uint x = 0; x < CHUNK_W; x++){ diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 9f3ac414..1baf9c35 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -19,6 +19,7 @@ namespace lua { int userdata_destructor(lua::State* L); std::string env_name(int env); + void dump_stack(lua::State*); inline bool getglobal(lua::State* L, const std::string& name) { lua_getglobal(L, name.c_str()); @@ -208,7 +209,7 @@ namespace lua { return lua_isnumber(L, idx); } inline bool isstring(lua::State* L, int idx) { - return lua_isstring(L, idx); + return lua_type(L, idx) == LUA_TSTRING; } inline bool istable(lua::State* L, int idx) { return lua_istable(L, idx); @@ -226,6 +227,11 @@ namespace lua { return lua_toboolean(L, idx); } inline lua::Integer tointeger(lua::State* L, int idx) { +#ifndef NDEBUG + if (lua_type(L, idx) == LUA_TSTRING) { + throw std::runtime_error("integer expected, got string"); + } +#endif return lua_tointeger(L, idx); } inline uint64_t touinteger(lua::State* L, int idx) { @@ -236,6 +242,11 @@ namespace lua { return static_cast(val); } inline lua::Number tonumber(lua::State* L, int idx) { +#ifndef NDEBUG + if (lua_type(L, idx) != LUA_TNUMBER && !lua_isnoneornil(L, idx)) { + throw std::runtime_error("integer expected"); + } +#endif return lua_tonumber(L, idx); } inline const char* tostring(lua::State* L, int idx) { @@ -588,7 +599,6 @@ namespace lua { } int create_environment(lua::State*, int parent); void remove_environment(lua::State*, int id); - void dump_stack(lua::State*); inline void close(lua::State* L) { lua_close(L); From 65fec4f4a9ba9a25d40ef3c9e0f22cde421c356d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 16 Jan 2025 05:59:43 +0300 Subject: [PATCH 12/36] introduce local player --- src/engine/Engine.cpp | 8 ++++---- src/engine/Engine.hpp | 8 +++++--- src/engine/Mainloop.cpp | 6 ++++-- src/engine/ServerMainloop.cpp | 2 +- src/frontend/debug_panel.cpp | 6 ++++++ src/frontend/screens/LevelScreen.cpp | 13 ++++++++----- src/frontend/screens/LevelScreen.hpp | 4 +++- src/logic/ChunksController.cpp | 6 ++++-- src/logic/EngineController.cpp | 16 +++++++++++----- src/logic/EngineController.hpp | 3 +++ src/logic/LevelController.cpp | 5 +++++ src/logic/PlayerController.cpp | 1 - src/logic/scripting/lua/libs/libcore.cpp | 6 ++++++ src/logic/scripting/lua/libs/libplayer.cpp | 13 +++++++++---- src/objects/Players.cpp | 13 +++++++++++-- src/objects/Players.hpp | 5 ++++- 16 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 9184fdd6..00382420 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -272,7 +272,7 @@ PacksManager Engine::createPacksManager(const fs::path& worldFolder) { return manager; } -void Engine::setLevelConsumer(consumer> levelConsumer) { +void Engine::setLevelConsumer(OnWorldOpen levelConsumer) { this->levelConsumer = std::move(levelConsumer); } @@ -446,14 +446,14 @@ void Engine::setLanguage(std::string locale) { langs::setup(paths.getResourcesFolder(), std::move(locale), contentPacks); } -void Engine::onWorldOpen(std::unique_ptr level) { +void Engine::onWorldOpen(std::unique_ptr level, int64_t localPlayer) { logger.info() << "world open"; - levelConsumer(std::move(level)); + levelConsumer(std::move(level), localPlayer); } void Engine::onWorldClosed() { logger.info() << "world closed"; - levelConsumer(nullptr); + levelConsumer(nullptr, -1); } void Engine::quit() { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index af9f7fb9..406d420a 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -53,6 +53,8 @@ struct CoreParameters { std::filesystem::path scriptFile; }; +using OnWorldOpen = std::function, int64_t)>; + class Engine : public util::ObjectsKeeper { CoreParameters params; EngineSettings settings; @@ -71,7 +73,7 @@ class Engine : public util::ObjectsKeeper { std::unique_ptr gui; PostRunnables postRunnables; Time time; - consumer> levelConsumer; + OnWorldOpen levelConsumer; bool quitSignal = false; void loadControls(); @@ -134,7 +136,7 @@ public: /// @brief Get engine resource paths controller ResPaths* getResPaths(); - void onWorldOpen(std::unique_ptr level); + void onWorldOpen(std::unique_ptr level, int64_t localPlayer); void onWorldClosed(); void quit(); @@ -166,7 +168,7 @@ public: PacksManager createPacksManager(const fs::path& worldFolder); - void setLevelConsumer(consumer> levelConsumer); + void setLevelConsumer(OnWorldOpen levelConsumer); SettingsHandler& getSettingsHandler(); diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index e0e64d10..2de6291d 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -15,14 +15,16 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) { void Mainloop::run() { auto& time = engine.getTime(); - engine.setLevelConsumer([this](auto level) { + engine.setLevelConsumer([this](auto level, int64_t localPlayer) { if (level == nullptr) { // destroy LevelScreen and run quit callbacks engine.setScreen(nullptr); // create and go to menu screen engine.setScreen(std::make_shared(engine)); } else { - engine.setScreen(std::make_shared(engine, std::move(level))); + engine.setScreen(std::make_shared( + engine, std::move(level), localPlayer + )); } }); diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index b97919be..954c2a11 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -30,7 +30,7 @@ void ServerMainloop::run() { logger.info() << "nothing to do"; return; } - engine.setLevelConsumer([this](auto level) { + engine.setLevelConsumer([this](auto level, auto) { setLevel(std::move(level)); }); diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index a234c38a..936c3b2e 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -14,6 +14,7 @@ #include "graphics/render/ChunksRenderer.hpp" #include "logic/scripting/scripting.hpp" #include "objects/Player.hpp" +#include "objects/Players.hpp" #include "objects/Entities.hpp" #include "objects/EntityDef.hpp" #include "physics/Hitbox.hpp" @@ -41,6 +42,7 @@ static std::shared_ptr