From 0d5423a97010f91399104b80dc9ea84d6f8a2c41 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 28 Nov 2024 11:36:18 +0300 Subject: [PATCH 01/56] update README.md and main-page.md --- README.md | 2 +- doc/en/main-page.md | 4 +--- doc/ru/main-page.md | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 01bc864b..bf1580b3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Latest release - [Download](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) -- [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) +- [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md) ## Build project in Linux diff --git a/doc/en/main-page.md b/doc/en/main-page.md index 4d487f5a..21d4dc95 100644 --- a/doc/en/main-page.md +++ b/doc/en/main-page.md @@ -1,8 +1,6 @@ # Documentation -Documentation for the engine of in-development version 0.25. - -[Documentation for stable release 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) +Documentation for stable release 0.24.x. ## Sections diff --git a/doc/ru/main-page.md b/doc/ru/main-page.md index 800415c6..05269cee 100644 --- a/doc/ru/main-page.md +++ b/doc/ru/main-page.md @@ -1,8 +1,6 @@ # Документация -Документация движка разрабатываемой версии 0.25. - -[Документация стабильной версии 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) +Документация стабильной версии 0.25.x. ## Разделы From bcbd56e3a95b26a3a2bba57ed2ee41bdee04b356 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 28 Nov 2024 12:08:05 +0300 Subject: [PATCH 02/56] update CHANGELOG.md to 0.25 --- CHANGELOG.md | 198 ++++++++++++++++++++------------------------------- 1 file changed, 77 insertions(+), 121 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db70633..ff05ca38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,138 +1,94 @@ -# 0.24 - 2024.11.07 +# 0.25 - 2024.11.29 -[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.24/doc/en/main-page.md) for 0.24 +[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.25/doc/en/main-page.md) for 0.25 Table of contents: - [Added](#added) - [Functions](#functions) -- [Changes](#changes) - [Fixes](#fixes) ## Added -- particles -- VEC3 models support -- handhold item display -- rules -- events: - - on_block_broken (documented) - - on_block_placed (documented) - - on_block_interact +- 3dtext +- blockwraps +- network (http requests and sockets) - libraries: - - gfx.particles - - utf8 - - rules -- bindings: - - player.destroy - - player.fast_interaction -- water overlay -- block models from OBJ or VEC3 -- bicubic heightmaps interpolation method -- unicode escapes support -- fragments placements -- console commands: - - time.daycycle - - fragment.place - - rule.list - - rule.set -- text field 'subconsumer' -- shader uniforms: - - u_lightDir to main shader - - u_dayTime to skybox shader -- block properties: - - overlay-texture - - model-name -- item properties: - - model-name -- 'Open content folder' buttons -- 'Background framerate limit' setting + - base64 + - gfx.text3d + - gfx.blockwraps + - network +- events: + - on_replaced + - on_block_replaced +- structures 'lowering' property +- add 'hint' property to textbox +- add 'taking' and 'placing' properties to slot and slotsgrid +- add 'scroll-step' property to container +- add 'line-numbers' and 'text-color' to textbox +- modules: + - base:util +- uinode property 'id' +- block.materials table +- block.properties table +- item.properties table +- add version to world info table +- add 'sizeSpread' particles property ### Functions -- core.open_folder -- world.get_generator -- world.is_open -- item.placing_block -- item.model_name -- item.emission -- entities.get_hitbox -- utf8.tobytes -- utf8.tostring -- utf8.length -- utf8.codepoint -- utf8.encode -- utf8.sub -- utf8.upper -- utf8.lower -- file.read_combined_object -- fragment:place -- rules.create -- rules.listen -- rules.unlisten -- rules.get -- rules.set -- rules.reset -- input.set_enabled -- hud._is_content_access -- hud._set_content_access -- hud._set_debug_cheats -- gfx.particles.emit -- gfx.particles.stop -- gfx.particles.get_origin -- gfx.particles.set_origin -- assets.load_texture - -Documented: -- file.read_combined_list -- file.list -- file.list_all_res -- input.is_active -- table.copy -- table.count_pairs -- table.random -- table.has -- table.index -- table.remove_value -- table.tostring -- string.explode -- string.split -- string.pattern_safe -- string.formatted_time -- string.replace -- string.trim -- string.trim_left -- string.trim_right -- string.starts_with -- string.ends_with -- math.clamp -- math.rand -- is_array -- parse_path -- timeit -- sleep - -## Changes - -- major skybox optimization -- chunks-renderer optimization -- libspng replaced with libpng on Windows -- console commands: - - blocks.fill - - fragment.save -- added 'def' to core.get_setting_info tables -- water texture +- player.is_infinite_items +- player.set_infinite_items +- player.is_instant_destruction +- player.set_instant_destruction +- player.get_name +- player.set_name +- hud.open +- base64.encode +- base64.decode +- utf8.escape +- string.escape +- textbox:lineAt +- textbox:linePos +- network.get +- network.get_binary +- network.tcp_connect +- network.tcp_open +- network.get_total_upload +- network.get_total_download +- gfx.text3d.show +- gfx.text3d.hide +- gfx.text3d.get_text +- gfx.text3d.set_text +- gfx.text3d.get_pos +- gfx.text3d.set_pos +- gfx.text3d.get_axis_x +- gfx.text3d.set_axis_x +- gfx.text3d.get_axis_y +- gfx.text3d.set_axis_y +- gfx.text3d.set_rotation +- gfx.text3d.update_settings ## Fixes -- [fix fatal error on editing texbox not having any consumer](https://github.com/MihailRis/VoxelEngine-Cpp/commit/22fa082fc6299ffa3196d62c67e01b849c35b8eb) -- [fix commands boolean type support](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a50cb109c8e3ca0f7a591bf126f07aee36c962e6) -- [fix potential null dereferences on incorrect block.* functions use](https://github.com/MihailRis/VoxelEngine-Cpp/commit/961773c9f9745c15eb8d697c1538ac8e21f24da3) -- [fix: draw-group not copied](https://github.com/MihailRis/VoxelEngine-Cpp/commit/dc8bad2af67e70b0b2346f516028e5795f597737) -- [fix: generator-providing pack may be removed](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f2f365278eb1866c773890471b7269a5ef45305) -- [fix colision check on block place](https://github.com/MihailRis/VoxelEngine-Cpp/commit/726ee8ad703bc57530b881450b8839aaec6b97c9) -- [fix collision detection bug](https://github.com/MihailRis/VoxelEngine-Cpp/commit/7fcc34ba4cf14097dfda26054b028c5e8771d26c) -- [fix: blocks lighting bug fix](https://github.com/MihailRis/VoxelEngine-Cpp/commit/9d3e872f88de2648f8c0f2e4611b30f5ce8999cf) -- [fix: inaccurate framerate limit on Windows](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3f531bbf98da5ad751dce1220c5c5fdf35f86c92) -- [fix block.get_hitbox again](https://github.com/MihailRis/VoxelEngine-Cpp/commit/edad594101e5808ccf14e0edefedbe87cb8f983b) -- [fix string.replace](https://github.com/MihailRis/VoxelEngine-Cpp/commit/44fd5416a9a110a12f8b3f2d369e5638055b306e) +- [fix translucent blocks render](https://github.com/MihailRis/VoxelEngine-Cpp/pull/370) +- [fix blocks selection with semi-transparent blocks](https://github.com/MihailRis/VoxelEngine-Cpp/commit/171cbb48d099032d7e78c51a46c374104f96f0d1) +- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) +- [mip-mapping related fixes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d9277e1b31714632bd7f5f601b8362a9e7cb8819) +- [fix disabled slots display](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e8ee3e04b1398a3ada8445591267525304410571) +- [fix attack](https://github.com/MihailRis/VoxelEngine-Cpp/commit/bc17abc8b3ee7ff9027f7e3c375ca0330bb8e7bc) +- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) +- [fix stdlib.lua](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6ec33ab98c78523eaececf40f113f2323d25a33a) +- [fix file.write_bytes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0fec17a8b69ac81255b77022f3af5addf8fcc8f8) +- [fix World::nextInventoryId](https://github.com/MihailRis/VoxelEngine-Cpp/commit/371fdaedcef2c163edd226160f388068b2bf5e83) +- [fix block inventory unbinding](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f6c2a916afd6b9b79221111fc72b1a86109be13) +- [fix xml text escapes handling](https://github.com/MihailRis/VoxelEngine-Cpp/commit/53c54dc91d132c221ff5fea2f7e9fb4568db9a0f) +- [fix `\'` escape parsing](https://github.com/MihailRis/VoxelEngine-Cpp/commit/2bc6cbda2e809b14fa6cffe09161b53c1636675f) +- [fix crosshair look](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e034bda477c35efe96548e78ecc722966a7a2197) +- [fix: actual block inventory size not updating on inventory-size property update](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1ba5b0ce33103e539ccb199ee1cd52095e286a1f) +- [fix falling block hitbox](https://github.com/MihailRis/VoxelEngine-Cpp/commit/352ef6485a4b796d1cdc8dd0e00ab1a1d72a2c0a) +- [fix console position](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3ea213e8d3cee7be55ec39ffb18dc557dec7557b) +- [fix: fatal error on pack removal when no world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/78d5ab02c2ba8a3d05cf5639eb10a49c9ca14ec3) +- [fix custom model lighting](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a333cadfcaeb485a30833343d55faf01b28a5c5f) +- [fix: emitter does not skip particles](https://github.com/MihailRis/VoxelEngine-Cpp/commit/983e516fb4ebc1f2def592f2b7f3195d968deed2) +- [fix old custom models render](https://github.com/MihailRis/VoxelEngine-Cpp/commit/82733d38011b52a426cb74560521949c1cd43cc1) From ef35efe049ba426d88aecad50c6764ea57d0548b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 28 Nov 2024 12:10:13 +0300 Subject: [PATCH 03/56] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf1580b3..d7985dee 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ cmake --build . ### Install libraries ```sh -brew install glfw3 glew glm libpng libvorbis lua luajit openal-soft skypjack/entt/entt +brew install glfw3 glew glm libpng libvorbis lua luajit libcurl openal-soft skypjack/entt/entt ``` > [!TIP] From 6322c039587d4f8556545e7caebdf7d663f5290c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 28 Nov 2024 16:03:20 +0300 Subject: [PATCH 04/56] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff05ca38..18ad0682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ Table of contents: - item.properties table - add version to world info table - add 'sizeSpread' particles property +- add user properties ### Functions From 166f3199fad84d2c8f46547fe8f2e999333ec33c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 29 Nov 2024 21:22:34 +0300 Subject: [PATCH 05/56] update changelog date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ad0682..d2325bf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.25 - 2024.11.29 +# 0.25 - 2024.11.30 [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.25/doc/en/main-page.md) for 0.25 From 00cf6e39efd0a39d09af2fb573063afaec81c78c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 30 Nov 2024 17:34:07 +0300 Subject: [PATCH 06/56] fix projected text frustum culling --- src/graphics/render/TextsRenderer.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/graphics/render/TextsRenderer.cpp b/src/graphics/render/TextsRenderer.cpp index ea9a69e4..fa24b61b 100644 --- a/src/graphics/render/TextsRenderer.cpp +++ b/src/graphics/render/TextsRenderer.cpp @@ -65,12 +65,7 @@ void TextsRenderer::renderNote( xvec *= 1.0f + scale; yvec *= 1.0f + scale; } - if (preset.displayMode != NoteDisplayMode::PROJECTED) { - if (!frustum.isBoxVisible(pos - xvec * (width * 0.5f), - pos + xvec * (width * 0.5f))) { - return; - } - } else { + if (preset.displayMode == NoteDisplayMode::PROJECTED) { float scale = 1.0f; if (glm::abs(preset.perspective) > 0.0001f) { float scale2 = scale / @@ -99,6 +94,9 @@ void TextsRenderer::renderNote( pos = screenPos / screenPos.w; } + } else if (!frustum.isBoxVisible(pos - xvec * (width * 0.5f * preset.scale), + pos + xvec * (width * 0.5f * preset.scale))) { + return; } auto color = preset.color; batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity)); From 3e949bd4994f1f326b83e7c64536120305995fe0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 30 Nov 2024 22:14:37 +0300 Subject: [PATCH 07/56] fix fatal error on invalid base64.decode input string --- src/util/stringutil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 588da4a4..ac80d134 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -349,7 +349,7 @@ std::string util::mangleid(uint64_t value) { util::Buffer util::base64_decode(const char* str, size_t size) { util::Buffer bytes((size / 4) * 3); ubyte* dst = bytes.data(); - for (size_t i = 0; i < size;) { + for (size_t i = 0; i < (size / 4) * 4;) { ubyte a = base64_decode_char(ubyte(str[i++])); ubyte b = base64_decode_char(ubyte(str[i++])); ubyte c = base64_decode_char(ubyte(str[i++])); From 21c76c1b0d9d6d2eaaf724816a1d3475a0c0368c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 30 Nov 2024 22:32:14 +0300 Subject: [PATCH 08/56] add socket:get_address, serversocket:get_port --- doc/en/scripting/builtins/libnetwork.md | 6 ++++ doc/ru/scripting/builtins/libnetwork.md | 6 ++++ res/scripts/classes.lua | 2 ++ src/logic/scripting/lua/libs/libnetwork.cpp | 20 +++++++++++ src/network/Network.cpp | 40 ++++++++++++++------- src/network/Network.hpp | 4 +++ 6 files changed, 66 insertions(+), 12 deletions(-) diff --git a/doc/en/scripting/builtins/libnetwork.md b/doc/en/scripting/builtins/libnetwork.md index 1e519d9d..8f4b01eb 100644 --- a/doc/en/scripting/builtins/libnetwork.md +++ b/doc/en/scripting/builtins/libnetwork.md @@ -59,6 +59,9 @@ socket:is_alive() --> bool -- Checks if the connection is present (using socket:send(...) is available). socket:is_connected() --> bool + +-- Returns the address and port of the connection. +socket:get_address() --> str, int ``` ```lua @@ -80,6 +83,9 @@ server:close() -- Checks if the TCP server exists and is open. server:is_open() --> bool + +-- Returns the server port. +server:get_port() --> int ``` ## Analytics diff --git a/doc/ru/scripting/builtins/libnetwork.md b/doc/ru/scripting/builtins/libnetwork.md index 8a937330..a2304ed9 100644 --- a/doc/ru/scripting/builtins/libnetwork.md +++ b/doc/ru/scripting/builtins/libnetwork.md @@ -59,6 +59,9 @@ socket:is_alive() --> bool -- Проверяет наличие соединения (доступно использование socket:send(...)). socket:is_connected() --> bool + +-- Возвращает адрес и порт соединения. +socket:get_address() --> str, int ``` ```lua @@ -80,6 +83,9 @@ server:close() -- Проверяет, существует и открыт ли TCP сервер. server:is_open() --> bool + +-- Возвращает порт сервера. +server:get_port() --> int ``` ## Аналитика diff --git a/res/scripts/classes.lua b/res/scripts/classes.lua index 200f305f..909717cf 100644 --- a/res/scripts/classes.lua +++ b/res/scripts/classes.lua @@ -42,6 +42,7 @@ local Socket = {__index={ close=function(self) return network.__close(self.id) end, is_alive=function(self) return network.__is_alive(self.id) end, is_connected=function(self) return network.__is_connected(self.id) end, + get_address=function(self) return network.__get_address(self.id) end, }} network.tcp_connect = function(address, port, callback) @@ -55,6 +56,7 @@ end local ServerSocket = {__index={ close=function(self) return network.__closeserver(self.id) end, is_open=function(self) return network.__is_serveropen(self.id) end, + get_port=function(self) return network.__get_serverport(self.id) end, }} network.tcp_open = function(port, handler) diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 7f503c23..cce00067 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -151,6 +151,16 @@ static int l_is_connected(lua::State* L) { return lua::pushboolean(L, false); } +static int l_get_address(lua::State* L) { + u64id_t id = lua::tointeger(L, 1); + if (auto connection = engine->getNetwork().getConnection(id)) { + lua::pushstring(L, connection->getAddress()); + lua::pushinteger(L, connection->getPort()); + return 2; + } + return 0; +} + static int l_is_serveropen(lua::State* L) { u64id_t id = lua::tointeger(L, 1); if (auto server = engine->getNetwork().getServer(id)) { @@ -159,6 +169,14 @@ static int l_is_serveropen(lua::State* L) { return lua::pushboolean(L, false); } +static int l_get_serverport(lua::State* L) { + u64id_t id = lua::tointeger(L, 1); + if (auto server = engine->getNetwork().getServer(id)) { + return lua::pushinteger(L, server->getPort()); + } + return 0; +} + static int l_get_total_upload(lua::State* L) { return lua::pushinteger(L, engine->getNetwork().getTotalUpload()); } @@ -180,6 +198,8 @@ const luaL_Reg networklib[] = { {"__recv", lua::wrap}, {"__is_alive", lua::wrap}, {"__is_connected", lua::wrap}, + {"__get_address", lua::wrap}, {"__is_serveropen", lua::wrap}, + {"__get_serverport", lua::wrap}, {NULL, NULL} }; diff --git a/src/network/Network.cpp b/src/network/Network.cpp index 5a1931ac..5036d65a 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -244,10 +244,11 @@ static inline int sendsocket( return send(descriptor, buf, len, flags); } -static std::string to_string(const sockaddr_in* addr) { +static std::string to_string(const sockaddr_in& addr, bool port=true) { char ip[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN)) { - return std::string(ip)+":"+std::to_string(htons(addr->sin_port)); + if (inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN)) { + return std::string(ip) + + (port ? (":" + std::to_string(htons(addr.sin_port))) : ""); } return ""; } @@ -266,7 +267,7 @@ class SocketConnection : public Connection { void connectSocket() { state = ConnectionState::CONNECTING; - logger.info() << "connecting to " << to_string(&addr); + logger.info() << "connecting to " << to_string(addr); int res = connectsocket(descriptor, (const sockaddr*)&addr, sizeof(sockaddr_in)); if (res < 0) { auto error = handle_socket_error("Connect failed"); @@ -275,7 +276,7 @@ class SocketConnection : public Connection { logger.error() << error.what(); return; } - logger.info() << "connected to " << to_string(&addr); + logger.info() << "connected to " << to_string(addr); state = ConnectionState::CONNECTED; } public: @@ -301,13 +302,13 @@ public: while (state == ConnectionState::CONNECTED) { int size = recvsocket(descriptor, buffer.data(), buffer.size()); if (size == 0) { - logger.info() << "closed connection with " << to_string(&addr); + logger.info() << "closed connection with " << to_string(addr); closesocket(descriptor); state = ConnectionState::CLOSED; break; } else if (size < 0) { logger.info() << "an error ocurred while receiving from " - << to_string(&addr); + << to_string(addr); auto error = handle_socket_error("recv(...) error"); closesocket(descriptor); state = ConnectionState::CLOSED; @@ -321,7 +322,7 @@ public: } totalDownload += size; } - logger.info() << "read " << size << " bytes from " << to_string(&addr); + logger.info() << "read " << size << " bytes from " << to_string(addr); } }); } @@ -380,6 +381,14 @@ public: return size; } + int getPort() const override { + return htons(addr.sin_port); + } + + std::string getAddress() const override { + return to_string(addr, false); + } + static std::shared_ptr connect( const std::string& address, int port, runnable callback ) { @@ -421,9 +430,10 @@ class SocketTcpSServer : public TcpServer { std::mutex clientsMutex; bool open = true; std::unique_ptr thread = nullptr; + int port; public: - SocketTcpSServer(Network* network, SOCKET descriptor) - : network(network), descriptor(descriptor) {} + SocketTcpSServer(Network* network, SOCKET descriptor, int port) + : network(network), descriptor(descriptor), port(port) {} ~SocketTcpSServer() { closeSocket(); @@ -445,7 +455,7 @@ public: close(); break; } - logger.info() << "client connected: " << to_string(&address); + logger.info() << "client connected: " << to_string(address); auto socket = std::make_shared( clientDescriptor, address ); @@ -488,6 +498,11 @@ public: bool isOpen() override { return open; } + + int getPort() const override { + return port; + } + static std::shared_ptr openServer( Network* network, int port, consumer handler ) { @@ -515,7 +530,8 @@ public: throw std::runtime_error("could not bind port "+std::to_string(port)); } logger.info() << "opened server at port " << port; - auto server = std::make_shared(network, descriptor); + auto server = + std::make_shared(network, descriptor, port); server->startListen(std::move(handler)); return server; } diff --git a/src/network/Network.hpp b/src/network/Network.hpp index 756784f4..c6170f39 100644 --- a/src/network/Network.hpp +++ b/src/network/Network.hpp @@ -46,6 +46,9 @@ namespace network { virtual size_t pullUpload() = 0; virtual size_t pullDownload() = 0; + virtual int getPort() const = 0; + virtual std::string getAddress() const = 0; + virtual ConnectionState getState() const = 0; }; @@ -55,6 +58,7 @@ namespace network { virtual void startListen(consumer handler) = 0; virtual void close() = 0; virtual bool isOpen() = 0; + virtual int getPort() const = 0; }; class Network { From 13cbe3fb176dac5523dc76febf2c7c44457b8b02 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 1 Dec 2024 10:37:27 +0300 Subject: [PATCH 09/56] update doc/*/events.md --- doc/en/scripting/events.md | 6 ++++++ doc/ru/scripting/events.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/doc/en/scripting/events.md b/doc/en/scripting/events.md index 4b13ec7b..cc820898 100644 --- a/doc/en/scripting/events.md +++ b/doc/en/scripting/events.md @@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid) Called on block placed by player +```lua +function on_block_replaced(blockid, x, y, z, playerid) +``` + +Called on block replaced with other by player + ```lua function on_block_broken(blockid, x, y, z, playerid) ``` diff --git a/doc/ru/scripting/events.md b/doc/ru/scripting/events.md index 08192cfa..a5cc3e72 100644 --- a/doc/ru/scripting/events.md +++ b/doc/ru/scripting/events.md @@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid) Вызывается после установки блока игроком +```lua +function on_block_replaced(blockid, x, y, z, playerid) +``` + +Вызывается после замены блока игроком + ```lua function on_block_broken(blockid, x, y, z, playerid) ``` From 3d97cd444ad028d80695c71f48c6e00da2222825 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 1 Dec 2024 12:10:26 +0300 Subject: [PATCH 10/56] update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2325bf4..4cd1b791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 0.25 - 2024.11.30 +# 0.25 - 2024.12.01 [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.25/doc/en/main-page.md) for 0.25 From 10eb26276a2df14c99dc00fe50d29d895c178b00 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 1 Dec 2024 12:11:14 +0300 Subject: [PATCH 11/56] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd1b791..845cedc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Table of contents: - events: - on_replaced - on_block_replaced + - on_player_tick - structures 'lowering' property - add 'hint' property to textbox - add 'taking' and 'placing' properties to slot and slotsgrid From 98e6ff26d8208a03d5677d9d6e3319bf82f3fa57 Mon Sep 17 00:00:00 2001 From: Rost Alexeev <148265518+R0STUS@users.noreply.github.com> Date: Sun, 1 Dec 2024 14:40:52 +0200 Subject: [PATCH 12/56] Update README.md entt in arch linux --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d7985dee..418d372c 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,12 @@ If you use Wayland sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl ``` +And you need entt. In yay you can use + +```sh +yay -S entt +``` + ### Build engine with CMake ```sh From d558b206a20d6057417b643d197ab816662b2b5e Mon Sep 17 00:00:00 2001 From: Anton Gushcha Date: Sun, 1 Dec 2024 21:11:27 +0700 Subject: [PATCH 13/56] Add missing curl dependency to nix build --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a1c9d20b..2c392d27 100644 --- a/flake.nix +++ b/flake.nix @@ -8,7 +8,7 @@ flake-utils.lib.eachDefaultSystem (system: { devShells.default = with nixpkgs.legacyPackages.${system}; mkShell { nativeBuildInputs = [ cmake pkg-config ]; - buildInputs = [ glm glfw glew zlib libpng libvorbis openal luajit ]; # libglvnd + buildInputs = [ glm glfw glew zlib libpng libvorbis openal luajit curl ]; # libglvnd packages = [ glfw mesa freeglut entt ]; LD_LIBRARY_PATH = "${wayland}/lib:$LD_LIBRARY_PATH"; }; From d8266ec5169302a5318264ffbb92042f1e136a06 Mon Sep 17 00:00:00 2001 From: Zohidjon Date: Sun, 1 Dec 2024 19:26:13 +0500 Subject: [PATCH 14/56] Added the translation of missing terms and updated the old ones. --- res/texts/uz_UZ.txt | 94 +++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/res/texts/uz_UZ.txt b/res/texts/uz_UZ.txt index 0ad6ec37..9d017ce9 100644 --- a/res/texts/uz_UZ.txt +++ b/res/texts/uz_UZ.txt @@ -1,4 +1,4 @@ -# Общее +# Umumiy Yes=Ha No=Yo'q Ok=Ок @@ -10,18 +10,26 @@ Version=Versiya Creator=Muallif Dependencies=Bog'liqliklar Description=Tavsif -Converting world...=Dunyoni konvertatsiyalash amalga oshirilyapti... +Converting world...=Dunyo konvertatsiya qilinmoqda... Unlimited=Cheksiz +Chat=Suhbat +Console=Konsol +Log=log +Problems=Muammolar +Monitor=Monitoring +Debug=Xatolarni tuzatish (Debug) +File=Fayl +devtools.traceback=Chaqiruvlar steki (so‘nggisidan boshlab) error.pack-not-found=Paketni topib bo'lmadi error.dependency-not-found=Amaldagi qaramliklar topilmadi -pack.remove-confirm=Paketlar bilan taqdim etilgan barcha mazmunni dunyodan olib tashlash (qaytarib bo'lmaydi)? +pack.remove-confirm=Paketlar bilan taqdim etilgan barcha contentni dunyodan olib tashlash (qaytarib bo'lmaydi)? -# Подсказки +# Maslahatlar graphics.gamma.tooltip=Yorug'lik yorqinligi egri chizig'i graphics.backlight.tooltip=To'liq zulmatni oldini oladigan orqa yorug'ligi -# Меню +# Menyu menu.Apply=Qo'llash menu.Audio=Tovush menu.Back to Main Menu=Menyuga qaytish @@ -31,61 +39,73 @@ menu.Continue=Davom ettirish menu.Controls=Boshqaruv menu.Display=Displey menu.Graphics=Grafika -menu.missing-content=Kontent etishmayapti! +menu.missing-content=Kontent mavjud emas! menu.New World=Yangi Dunyo -menu.Worlds=Dunyo -menu.Open worlds folder=Dunyo papkasini ochish +menu.Open worlds folder=Dunyolar papkasini ochish +menu.Worlds=Dunyolar menu.Page not found=Sahifa topilmadi menu.Quit=Chiqish -menu.Save and Quit to Menu=Saqlash va menyuga chiqish +menu.Save and Quit to Menu=Saqlash va Menyuga chiqish menu.Settings=Sozlamalar -menu.Contents Menu=Kontent to'plamlari menyusi +menu.Reset settings=Sozlamalarni tiklash +menu.Contents Menu=Kontent paklar menyusi +menu.Open data folder=Ma'lumotlar papkasini ochish +menu.Open content folder=[content] papkasini ochish world.Seed=Don world.Name=Nom -world.World generator=Dunyo yaratuvchi -world.generators.default=Oddiy -world.generators.flat=Yassi -world.Create World=Dunyoni Yaratish -world.convert-request=Indekslarda o‘zgarishlar mavjud! Dunyoni konvertatsiya qilish kerakmi? -world.delete-confirm=Dunyoni qaytarib bo'lmaydigan tarzda olib tashlaysizmi? +world.World generator=Dunyo generatori +world.generators.default=Standart bo'yicha +world.generators.flat=Tekis +world.Create World=Dunyo yaratish +world.convert-request=Indekslar bo'yicha o'zgarishlar bor! Dunyoni konvertatsiya qilasizmi? +world.upgrade-request=Dunyo formati eskirgan! Dunyoni konvertatsiya qilasizmi? +world.convert-with-loss=Dunyoni yo'qotishlar bilan konvertatsiya qilasizmi? +world.convert-block-layouts=Blok maydonlarida o'zgarishlar bor! Dunyoni konvertatsiya qilasizmi? +world.delete-confirm=Dunyoni doimiy o'chirasizmi? -# Настройки +# Sozlamalar settings.Ambient=Fon settings.Backlight=Yoritish -settings.Camera Shaking=Kamera Silkinishi -settings.Camera Inertia=Kamera Inertsiyasi -settings.Fog Curve=Tuman Egri Chizig'i -settings.FOV=Ko'rish Maydoni +settings.Camera Shaking=Kamera titrashi +settings.Camera Inertia=Kamera inertsiyasi +settings.Camera FOV Effects=Ko'rish maydoni effektlari +settings.Fog Curve=Tuman egri chizig'i +settings.FOV=Ko'rish maydoni settings.Fullscreen=To'liq ekran -settings.Framerate=Kadr tezligi +settings.Framerate=Kadrlar chastotasi settings.Gamma=Gamma settings.Language=Til -settings.Load Distance=Yuklash Masofasi -settings.Load Speed=Yuklash Tezligi -settings.Master Volume=Umumiy Ovoz Balandligi -settings.Mouse Sensitivity=Sichqoncha Sezgirligi +settings.Load Distance=Yuklash masofasi +settings.Load Speed=Yuklash tezligi +settings.Master Volume=Umumiy ovoz balansi +settings.Mouse Sensitivity=Sichqoncha sezgirligi settings.Music=Musiqa -settings.Regular Sounds=Oddiy Tovushlar -settings.UI Sounds=Interfeys Tovushlari -settings.V-Sync=Vertikal Sinxronizatsiya +settings.Regular Sounds=Oddiy tovushlar +settings.UI Sounds=Interfeys tovushlari +settings.V-Sync=Vertikal sinxronizatsiya +settings.Key=Tugma +settings.Controls Search Mode=Tayinlangan boshqaruv tugmasi bo'yicha qidirish +settings.Limit Background FPS=Fon kadrlar chastotasini cheklash -# Управление +# Boshqaruv chunks.reload=Chanklarni qayta yuklash devtools.console=Konsol movement.forward=Oldinga movement.back=Orqaga movement.left=Chapga -movement.right=O'ng tomonda +movement.right=O'ngga movement.jump=Sakrash -movement.sprint=Tezlanish +movement.sprint=Tez yugurish movement.crouch=Egilish -movement.cheat=Chit -hud.inventory=inventar +movement.cheat=Hiyla (Chit) +hud.inventory=Inventar player.pick=Blokni olish -player.attack=Hujum Qilish / Sindirish -player.build=Blokni Joylashtiring +player.attack=Hujum qilish +player.destroy=Sindirish +player.build=Blokni qo'yish +player.fast_interaction=Tezkor o'zaro ta'sir player.flight=Parvoz player.drop=Narsani tashlash camera.zoom=Yaqinlashish -camera.mode=Kamera Rejimini O'zgartiring +camera.mode=Kamera Rejimini O'zgartiring \ No newline at end of file From 49defaeb3b2fd51f82f0d00a4f3dcf6964cc0e8f Mon Sep 17 00:00:00 2001 From: REDxEYE Date: Mon, 2 Dec 2024 02:33:38 +0300 Subject: [PATCH 15/56] Add api to serialize and deserialize chunk to bytes --- src/logic/scripting/lua/libs/libworld.cpp | 99 ++++++++++++++++++++--- 1 file changed, 88 insertions(+), 11 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 5422c873..b51bc7f8 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -1,16 +1,20 @@ #include -#include #include +#include +#include "api_lua.hpp" #include "assets/Assets.hpp" #include "assets/AssetsLoader.hpp" +#include "coders/gzip.hpp" #include "coders/json.hpp" #include "engine.hpp" -#include "files/files.hpp" #include "files/engine_paths.hpp" +#include "files/files.hpp" +#include "lighting/Lighting.hpp" +#include "voxels/Chunk.hpp" +#include "voxels/Chunks.hpp" #include "world/Level.hpp" #include "world/World.hpp" -#include "api_lua.hpp" using namespace scripting; namespace fs = std::filesystem; @@ -36,12 +40,12 @@ static int l_get_list(lua::State* L) { const auto& folder = worlds[i]; - auto root = json::parse(files::read_string(folder/fs::u8path("world.json"))); + auto root = + json::parse(files::read_string(folder / fs::u8path("world.json"))); const auto& versionMap = root["version"]; int versionMajor = versionMap["major"].asInteger(); int versionMinor = versionMap["minor"].asInteger(); - auto name = folder.filename().u8string(); lua::pushstring(L, name); lua::setfield(L, "name"); @@ -49,11 +53,11 @@ static int l_get_list(lua::State* L) { auto assets = engine->getAssets(); std::string icon = "world#" + name + ".icon"; if (!AssetsLoader::loadExternalTexture( - assets, - icon, - {worlds[i] / fs::path("icon.png"), - worlds[i] / fs::path("preview.png")} - )) { + assets, + icon, + {worlds[i] / fs::path("icon.png"), + worlds[i] / fs::path("preview.png")} + )) { icon = "gui/no_world_icon"; } lua::pushstring(L, icon); @@ -115,6 +119,76 @@ static int l_get_generator(lua::State* L) { return lua::pushstring(L, require_world_info().generator); } +static int l_get_chunk_data(lua::State* L) { + int x = (int)lua::tointeger(L, 1); + int y = (int)lua::tointeger(L, 2); + const auto& chunk = level->chunks->getChunk(x, y); + if (chunk->isEmpty()) { + return 0; + } + + bool compress = false; + if (lua::gettop(L) >= 3) { + compress = lua::toboolean(L, 3); + } + + if (compress) { + return lua::newuserdata( + L, gzip::compress(chunk->encode().get(), CHUNK_DATA_LEN) + ); + } + const auto chunk_data = chunk->encode(); + const std::vector data( + chunk_data.get(), chunk_data.get() + CHUNK_DATA_LEN + ); + return lua::newuserdata(L, data); +} + +static int l_set_chunk_data(lua::State* L) { + int x = (int)lua::tointeger(L, 1); + int y = (int)lua::tointeger(L, 2); + auto buffer = lua::touserdata(L, 3); + bool is_compressed = false; + if (lua::gettop(L) >= 4) { + is_compressed = lua::toboolean(L, 4); + } + auto chunk = level->chunks->getChunk(x, y); + if (is_compressed) { + auto data = + gzip::decompress(buffer->data().data(), buffer->data().size()); + chunk->decode(data.data()); + } else { + chunk->decode(buffer->data().data()); + } + chunk->updateHeights(); + level->lighting->buildSkyLight(x, y); + chunk->flags.modified = true; + level->lighting->onChunkLoaded(x, y, true); + + chunk = level->chunks->getChunk(x - 1, y); + if (chunk != nullptr) { + chunk->flags.modified = true; + level->lighting->onChunkLoaded(x - 1, y, true); + } + chunk = level->chunks->getChunk(x + 1, y); + if (chunk != nullptr) { + chunk->flags.modified = true; + level->lighting->onChunkLoaded(x + 1, y, true); + } + chunk = level->chunks->getChunk(x, y - 1); + if (chunk != nullptr) { + chunk->flags.modified = true; + level->lighting->onChunkLoaded(x, y - 1, true); + } + chunk = level->chunks->getChunk(x, y + 1); + if (chunk != nullptr) { + chunk->flags.modified = true; + level->lighting->onChunkLoaded(x, y + 1, true); + } + + return 1; +} + const luaL_Reg worldlib[] = { {"is_open", lua::wrap}, {"get_list", lua::wrap}, @@ -128,4 +202,7 @@ const luaL_Reg worldlib[] = { {"is_day", lua::wrap}, {"is_night", lua::wrap}, {"exists", lua::wrap}, - {NULL, NULL}}; + {"get_chunk_data", lua::wrap}, + {"set_chunk_data", lua::wrap}, + {NULL, NULL} +}; From 657069cd489f1085a49de20cd916014b248cc53c Mon Sep 17 00:00:00 2001 From: Onran <100285264+Onran0@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:57:26 +0900 Subject: [PATCH 16/56] migration to ByteArray + small fix --- res/modules/data_buffer.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/modules/data_buffer.lua b/res/modules/data_buffer.lua index aafe63e7..96377da3 100644 --- a/res/modules/data_buffer.lua +++ b/res/modules/data_buffer.lua @@ -33,7 +33,7 @@ local data_buffer = function data_buffer:new(bytes) local obj = { pos = 1, - bytes = bytes or { } + bytes = Bytearray(bytes or { }) } self.__index = self @@ -49,7 +49,7 @@ function data_buffer:put_byte(byte) error("invalid byte") end - self.bytes[self.pos] = byte + self.bytes:insert(self.pos, byte) self.pos = self.pos + 1 end @@ -247,4 +247,4 @@ end setmetatable(data_buffer, data_buffer) -return data_buffer \ No newline at end of file +return data_buffer From ad81e644616a8c773633a6a31971e506a7b84340 Mon Sep 17 00:00:00 2001 From: REDxEYE Date: Mon, 2 Dec 2024 21:26:44 +0300 Subject: [PATCH 17/56] Add EXTRLE16+GZIP combo for chunk compression --- CMakeLists.txt | 8 +++ src/logic/scripting/lua/libs/libworld.cpp | 65 ++++++++++++++++++----- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f465fcb3..61177810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,3 +82,11 @@ if (VOXELENGINE_BUILD_TESTS) enable_testing() add_subdirectory(test) endif() + +add_custom_target(copy_resources ALL + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/res + ${CMAKE_CURRENT_BINARY_DIR}/res + COMMENT "Copying resource directory to the build directory" +) +add_dependencies(${PROJECT_NAME} copy_resources) \ No newline at end of file diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index b51bc7f8..0d476d16 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -3,8 +3,8 @@ #include #include "api_lua.hpp" -#include "assets/Assets.hpp" #include "assets/AssetsLoader.hpp" +#include "coders/compression.hpp" #include "coders/gzip.hpp" #include "coders/json.hpp" #include "engine.hpp" @@ -123,7 +123,8 @@ static int l_get_chunk_data(lua::State* L) { int x = (int)lua::tointeger(L, 1); int y = (int)lua::tointeger(L, 2); const auto& chunk = level->chunks->getChunk(x, y); - if (chunk->isEmpty()) { + if (chunk == nullptr) { + lua::pushnil(L); return 0; } @@ -131,17 +132,42 @@ static int l_get_chunk_data(lua::State* L) { if (lua::gettop(L) >= 3) { compress = lua::toboolean(L, 3); } - + std::vector chunk_data; if (compress) { - return lua::newuserdata( - L, gzip::compress(chunk->encode().get(), CHUNK_DATA_LEN) + size_t rle_compressed_size; + size_t gzip_compressed_size; + const auto& data_ptr = chunk->encode(); + ubyte* data = data_ptr.get(); + const auto& rle_compressed_data_ptr = compression::compress( + data, + CHUNK_DATA_LEN, + rle_compressed_size, + compression::Method::EXTRLE16 + ); + const auto& gzip_compressed_data = compression::compress( + rle_compressed_data_ptr.get(), + rle_compressed_size, + gzip_compressed_size, + compression::Method::GZIP + ); + auto tmp = dataio::h2le(rle_compressed_size); + chunk_data.reserve(gzip_compressed_size + sizeof(tmp)); + chunk_data.insert( + chunk_data.begin() + 0, (char*)&tmp, ((char*)&tmp) + sizeof(tmp) + ); + chunk_data.insert( + chunk_data.begin() + sizeof(tmp), + gzip_compressed_data.get(), + gzip_compressed_data.get() + gzip_compressed_size + ); + } else { + const auto& data = chunk->encode(); + chunk_data.reserve(CHUNK_DATA_LEN); + chunk_data.insert( + chunk_data.begin(), data.get(), data.get() + CHUNK_DATA_LEN ); } - const auto chunk_data = chunk->encode(); - const std::vector data( - chunk_data.get(), chunk_data.get() + CHUNK_DATA_LEN - ); - return lua::newuserdata(L, data); + return lua::newuserdata(L, chunk_data); } static int l_set_chunk_data(lua::State* L) { @@ -154,9 +180,22 @@ static int l_set_chunk_data(lua::State* L) { } auto chunk = level->chunks->getChunk(x, y); if (is_compressed) { - auto data = - gzip::decompress(buffer->data().data(), buffer->data().size()); - chunk->decode(data.data()); + std::vector& raw_data = buffer->data(); + size_t gzip_decompressed_size = + dataio::le2h(*(size_t*)(raw_data.data())); + const auto& rle_data = compression::decompress( + raw_data.data() + sizeof(gzip_decompressed_size), + buffer->data().size() - sizeof(gzip_decompressed_size), + gzip_decompressed_size, + compression::Method::GZIP + ); + const auto& data = compression::decompress( + rle_data.get(), + gzip_decompressed_size, + CHUNK_DATA_LEN, + compression::Method::EXTRLE16 + ); + chunk->decode(data.get()); } else { chunk->decode(buffer->data().data()); } From 57e9cade7b9391f1a112271bfb910444e14b6594 Mon Sep 17 00:00:00 2001 From: REDxEYE Date: Mon, 2 Dec 2024 21:27:37 +0300 Subject: [PATCH 18/56] Potential nullptr access fix --- src/logic/scripting/lua/libs/libworld.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 0d476d16..99d2fec3 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -179,6 +179,9 @@ static int l_set_chunk_data(lua::State* L) { is_compressed = lua::toboolean(L, 4); } auto chunk = level->chunks->getChunk(x, y); + if(chunk== nullptr){ + return 0; + } if (is_compressed) { std::vector& raw_data = buffer->data(); size_t gzip_decompressed_size = From 33a64915ad91db9af2f09cc3b9fe5c54b5c773fb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 11:58:37 +0300 Subject: [PATCH 19/56] fix: tcp server not listening to clients --- src/network/Network.cpp | 60 ++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/network/Network.cpp b/src/network/Network.cpp index 5036d65a..f7490514 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -293,37 +293,46 @@ public: } } + void startListen() { + while (state == ConnectionState::CONNECTED) { + int size = recvsocket(descriptor, buffer.data(), buffer.size()); + if (size == 0) { + logger.info() << "closed connection with " << to_string(addr); + closesocket(descriptor); + state = ConnectionState::CLOSED; + break; + } else if (size < 0) { + logger.info() << "an error ocurred while receiving from " + << to_string(addr); + auto error = handle_socket_error("recv(...) error"); + closesocket(descriptor); + state = ConnectionState::CLOSED; + logger.error() << error.what(); + break; + } + { + std::lock_guard lock(mutex); + for (size_t i = 0; i < size; i++) { + readBatch.emplace_back(buffer[i]); + } + totalDownload += size; + } + logger.info() << "read " << size << " bytes from " << to_string(addr); + } + } + + void startClient() { + state = ConnectionState::CONNECTED; + thread = std::make_unique([this]() { startListen();}); + } + void connect(runnable callback) override { thread = std::make_unique([this, callback]() { connectSocket(); if (state == ConnectionState::CONNECTED) { callback(); } - while (state == ConnectionState::CONNECTED) { - int size = recvsocket(descriptor, buffer.data(), buffer.size()); - if (size == 0) { - logger.info() << "closed connection with " << to_string(addr); - closesocket(descriptor); - state = ConnectionState::CLOSED; - break; - } else if (size < 0) { - logger.info() << "an error ocurred while receiving from " - << to_string(addr); - auto error = handle_socket_error("recv(...) error"); - closesocket(descriptor); - state = ConnectionState::CLOSED; - logger.error() << error.what(); - break; - } - { - std::lock_guard lock(mutex); - for (size_t i = 0; i < size; i++) { - readBatch.emplace_back(buffer[i]); - } - totalDownload += size; - } - logger.info() << "read " << size << " bytes from " << to_string(addr); - } + startListen(); }); } @@ -459,6 +468,7 @@ public: auto socket = std::make_shared( clientDescriptor, address ); + socket->startClient(); u64id_t id = network->addConnection(socket); { std::lock_guard lock(clientsMutex); From ae754e3da2a72b92d4db450664a2610b1a0ec006 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 12:00:22 +0300 Subject: [PATCH 20/56] reduce log messages in release build --- src/network/Network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/Network.cpp b/src/network/Network.cpp index f7490514..57fcab40 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -302,7 +302,7 @@ public: state = ConnectionState::CLOSED; break; } else if (size < 0) { - logger.info() << "an error ocurred while receiving from " + logger.warning() << "an error ocurred while receiving from " << to_string(addr); auto error = handle_socket_error("recv(...) error"); closesocket(descriptor); @@ -317,7 +317,7 @@ public: } totalDownload += size; } - logger.info() << "read " << size << " bytes from " << to_string(addr); + logger.debug() << "read " << size << " bytes from " << to_string(addr); } } From 36edad039ceccfee5b5fc3f0e7b350e26fc1cec9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 12:05:10 +0300 Subject: [PATCH 21/56] add string socket:send overload --- doc/en/scripting/builtins/libnetwork.md | 2 +- doc/ru/scripting/builtins/libnetwork.md | 2 +- src/logic/scripting/lua/libs/libnetwork.cpp | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/en/scripting/builtins/libnetwork.md b/doc/en/scripting/builtins/libnetwork.md index 8f4b01eb..48caefbd 100644 --- a/doc/en/scripting/builtins/libnetwork.md +++ b/doc/en/scripting/builtins/libnetwork.md @@ -39,7 +39,7 @@ The Socket class has the following methods: ```lua -- Sends a byte array -socket:send(table|ByteArray) +socket:send(table|ByteArray|str) -- Reads the received data socket:recv( diff --git a/doc/ru/scripting/builtins/libnetwork.md b/doc/ru/scripting/builtins/libnetwork.md index a2304ed9..7fedf2bd 100644 --- a/doc/ru/scripting/builtins/libnetwork.md +++ b/doc/ru/scripting/builtins/libnetwork.md @@ -39,7 +39,7 @@ network.tcp_connect( ```lua -- Отправляет массив байт -socket:send(table|ByteArray) +socket:send(table|ByteArray|str) -- Читает полученные данные socket:recv( diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index cce00067..61d44de7 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -87,6 +87,9 @@ static int l_send(lua::State* L) { connection->send( reinterpret_cast(bytes->data().data()), bytes->data().size() ); + } else if (lua::isstring(L, 2)) { + auto string = lua::tolstring(L, 2); + connection->send(string.data(), string.length()); } return 0; } From 78b8305d78662f19d02a5e0927790bf2339ab23b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 13:39:33 +0300 Subject: [PATCH 22/56] set version to 0.26 --- doc/en/main-page.md | 4 +++- doc/ru/main-page.md | 4 +++- res/content/base/package.json | 2 +- src/constants.hpp | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/en/main-page.md b/doc/en/main-page.md index 21d4dc95..67db8c10 100644 --- a/doc/en/main-page.md +++ b/doc/en/main-page.md @@ -1,6 +1,8 @@ # Documentation -Documentation for stable release 0.24.x. +Documentation for in-development version 0.26. + +[Documentation for stable release 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md) ## Sections diff --git a/doc/ru/main-page.md b/doc/ru/main-page.md index 05269cee..17dbe6ba 100644 --- a/doc/ru/main-page.md +++ b/doc/ru/main-page.md @@ -1,6 +1,8 @@ # Документация -Документация стабильной версии 0.25.x. +Документация разрабатываемой версии 0.26. + +[Документация стабильной версии 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md) ## Разделы diff --git a/res/content/base/package.json b/res/content/base/package.json index 7645a6e0..2878d3a6 100644 --- a/res/content/base/package.json +++ b/res/content/base/package.json @@ -1,6 +1,6 @@ { "id": "base", "title": "Base", - "version": "0.25", + "version": "0.26", "description": "basic content package" } diff --git a/src/constants.hpp b/src/constants.hpp index 84d8b22c..c8de5a8d 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -6,7 +6,7 @@ #include inline constexpr int ENGINE_VERSION_MAJOR = 0; -inline constexpr int ENGINE_VERSION_MINOR = 25; +inline constexpr int ENGINE_VERSION_MINOR = 26; #ifdef NDEBUG inline constexpr bool ENGINE_DEBUG_BUILD = false; @@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false; inline constexpr bool ENGINE_DEBUG_BUILD = true; #endif // NDEBUG -inline const std::string ENGINE_VERSION_STRING = "0.25"; +inline const std::string ENGINE_VERSION_STRING = "0.26"; /// @brief world regions format version inline constexpr uint REGION_FORMAT_VERSION = 3; From 3e6e897ce82d3647ff9af010e73466712b8e79ad Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 13:59:29 +0300 Subject: [PATCH 23/56] fix png signature check --- src/coders/png.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coders/png.cpp b/src/coders/png.cpp index 60965ed1..b29afd34 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -13,7 +13,7 @@ static debug::Logger logger("png-coder"); // returns 0 if all-right, 1 otherwise -int _png_write( +static int png_write( const char* filename, uint width, uint height, const ubyte* data, bool alpha ) { uint pixsize = alpha ? 4 : 3; @@ -112,7 +112,7 @@ static void read_in_memory(png_structp pngPtr, png_bytep dst, png_size_t toread) } std::unique_ptr png::load_image(const ubyte* bytes, size_t size) { - if (!png_check_sig(bytes, size)) { + if (size < 8 || !png_check_sig(bytes, 8)) { throw std::runtime_error("invalid png signature"); } png_structp pngPtr = nullptr; @@ -223,7 +223,7 @@ std::unique_ptr png::load_texture(const std::string& filename) { } void png::write_image(const std::string& filename, const ImageData* image) { - _png_write( + png_write( filename.c_str(), image->getWidth(), image->getHeight(), From 28f49ac948371f99d8786f6c48ba75941323010d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 16:26:55 +0300 Subject: [PATCH 24/56] add Lua code tokenizer --- src/coders/commons.cpp | 18 ++++ src/coders/commons.hpp | 2 + src/coders/lua_parsing.cpp | 181 ++++++++++++++++++++++++++++++++++++ src/coders/lua_parsing.hpp | 35 +++++++ test/coders/lua_parsing.cpp | 20 ++++ 5 files changed, 256 insertions(+) create mode 100644 src/coders/lua_parsing.cpp create mode 100644 src/coders/lua_parsing.hpp create mode 100644 test/coders/lua_parsing.cpp diff --git a/src/coders/commons.cpp b/src/coders/commons.cpp index de4fb755..74fb87f5 100644 --- a/src/coders/commons.cpp +++ b/src/coders/commons.cpp @@ -214,6 +214,24 @@ std::string_view BasicParser::readUntil(char c) { return source.substr(start, pos - start); } +std::string_view BasicParser::readUntil(std::string_view s) { + int start = pos; + size_t found = source.find(s, pos); + if (found == std::string::npos) { + throw error(util::quote(std::string(s))+" expected"); + } + skip(found - pos); + return source.substr(start, pos - start); +} + +std::string_view BasicParser::readUntilWhitespace() { + int start = pos; + while (hasNext() && !is_whitespace(source[pos])) { + pos++; + } + return source.substr(start, pos - start); +} + std::string_view BasicParser::readUntilEOL() { int start = pos; while (hasNext() && source[pos] != '\r' && source[pos] != '\n') { diff --git a/src/coders/commons.hpp b/src/coders/commons.hpp index abd4c01a..c01601cb 100644 --- a/src/coders/commons.hpp +++ b/src/coders/commons.hpp @@ -105,6 +105,8 @@ protected: parsing_error error(const std::string& message); public: std::string_view readUntil(char c); + std::string_view readUntil(std::string_view s); + std::string_view readUntilWhitespace(); std::string_view readUntilEOL(); std::string parseName(); std::string parseXmlName(); diff --git a/src/coders/lua_parsing.cpp b/src/coders/lua_parsing.cpp new file mode 100644 index 00000000..f3ca21ef --- /dev/null +++ b/src/coders/lua_parsing.cpp @@ -0,0 +1,181 @@ +#include "lua_parsing.hpp" + +#include + +#include "commons.hpp" + +using namespace lua; + +static std::set keywords { + "and", "break", "do", "else", "elseif", "end", "false", "for", "function", + "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", + "until", "while" +}; + +bool lua::is_lua_keyword(std::string_view view) { + return keywords.find(view) != keywords.end(); +} + +inline bool is_lua_identifier_start(int c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; +} + +inline bool is_lua_identifier_part(int c) { + return is_lua_identifier_start(c) || is_digit(c); +} + +inline bool is_lua_operator_start(int c) { + return c == '=' || c == '~' || c == '+' || c == '-' || c == '/' || c == '*' + || c == '%' || c == '^' || c == '#' || c == '<' || c == '>' || c == ':' + || c == '.'; +} + +class Tokenizer : BasicParser { + std::vector tokens; +public: + Tokenizer(std::string_view file, std::string_view source) + : BasicParser(file, source) { + } + + std::string parseLuaName() { + char c = peek(); + if (!is_identifier_start(c)) { + throw error("identifier expected"); + } + int start = pos; + while (hasNext() && is_identifier_part(source[pos])) { + pos++; + } + return std::string(source.substr(start, pos - start)); + } + + inline Location currentLocation() const { + return Location { + static_cast(pos), + static_cast(linestart), + static_cast(line)}; + } + + void emitToken( + TokenTag tag, std::string name, Location start, bool standalone=false + ) { + tokens.emplace_back( + tag, + std::move(name), + std::move(start), + currentLocation() + ); + if (standalone) skip(1); + } + + /// @brief Get next operator token without checking operator for existing + std::string parseOperator() { + int start = pos; + char first = peek(); + switch (first) { + case '#': case '+': case '/': case '*': case '^': + case '%': + skip(1); + return std::string({first}); + case '-': + skip(1); + if (peekNoJump() == '-') { + skip(1); + return "--"; + } + return std::string({first}); + } + skip(1); + char second = peekNoJump(); + if ((first == '=' && second == '=') || (first == '~' && second == '=') || + (first == '<' && second == '=') || (first == '>' && second == '=')) { + skip(1); + return std::string(source.substr(start, pos - start)); + } + if (first == '.' && second == '.') { + skip(1); + if (peekNoJump() == '.') { + skip(1); + } + } + return std::string(source.substr(start, pos - start)); + } + + std::vector tokenize() { + skipWhitespace(); + while (hasNext()) { + skipWhitespace(); + if (!hasNext()) { + continue; + } + char c = peek(); + auto start = currentLocation(); + if (is_lua_identifier_start(c)) { + auto name = parseLuaName(); + emitToken( + is_lua_keyword(name) ? TokenTag::KEYWORD : TokenTag::NAME, + std::move(name), + start + ); + continue; + } else if (is_digit(c)) { + auto value = parseNumber(1); + auto literal = source.substr(start.pos, pos - start.pos); + emitToken( + value.isInteger() ? TokenTag::INTEGER : TokenTag::NUMBER, + std::string(literal), + start + ); + continue; + } + switch (c) { + case '(': case '[': case '{': + if (isNext("[==[")) { + readUntil("]==]"); + skip(4); + continue; + } else if (isNext("[[")) { + skip(2); + auto string = readUntil("]]"); + skip(2); + emitToken(TokenTag::STRING, std::string(string), start); + continue; + } + emitToken(TokenTag::OPEN_BRACKET, std::string({c}), start, true); + continue; + case ')': case ']': case '}': + emitToken(TokenTag::CLOSE_BRACKET, std::string({c}), start, true); + continue; + case ',': + emitToken(TokenTag::COMMA, std::string({c}), start, true); + continue; + case ';': + emitToken(TokenTag::SEMICOLON, std::string({c}), start, true); + continue; + case '\'': case '"': { + skip(1); + auto string = parseString(c); + emitToken(TokenTag::STRING, std::move(string), start); + continue; + } + default: break; + } + if (is_lua_operator_start(c)) { + auto text = parseOperator(); + if (text == "--") { + skipLine(); + continue; + } + emitToken(TokenTag::OPERATOR, std::move(text), start); + continue; + } + auto text = readUntilWhitespace(); + emitToken(TokenTag::UNEXPECTED, std::string(text), start); + } + return std::move(tokens); + } +}; + +std::vector lua::tokenize(std::string_view file, std::string_view source) { + return Tokenizer(file, source).tokenize(); +} diff --git a/src/coders/lua_parsing.hpp b/src/coders/lua_parsing.hpp new file mode 100644 index 00000000..68cc385a --- /dev/null +++ b/src/coders/lua_parsing.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace lua { + struct Location { + int pos; + int lineStart; + int line; + }; + + enum class TokenTag { + KEYWORD, NAME, INTEGER, NUMBER, OPEN_BRACKET, CLOSE_BRACKET, STRING, + OPERATOR, COMMA, SEMICOLON, UNEXPECTED + }; + + struct Token { + TokenTag tag; + std::string text; + Location start; + Location end; + + Token(TokenTag tag, std::string text, Location start, Location end) + : tag(tag), + text(std::move(text)), + start(std::move(start)), + end(std::move(end)) { + } + }; + + bool is_lua_keyword(std::string_view view); + + std::vector tokenize(std::string_view file, std::string_view source); +} diff --git a/test/coders/lua_parsing.cpp b/test/coders/lua_parsing.cpp new file mode 100644 index 00000000..9788d1d7 --- /dev/null +++ b/test/coders/lua_parsing.cpp @@ -0,0 +1,20 @@ +#include + +#include "coders/commons.hpp" +#include "coders/lua_parsing.hpp" +#include "files/files.hpp" +#include "util/stringutil.hpp" + +TEST(lua_parsing, Tokenizer) { + auto filename = "../../res/scripts/stdlib.lua"; + auto source = files::read_string(std::filesystem::u8path(filename)); + try { + auto tokens = lua::tokenize(filename, source); + for (const auto& token : tokens) { + std::cout << (int)token.tag << " " << util::quote(token.text) << std::endl; + } + } catch (const parsing_error& err) { + std::cerr << err.errorLog() << std::endl; + throw err; + } +} From b15725913e4370d878b3bfde6b4c086e40c3697e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 17:08:04 +0300 Subject: [PATCH 25/56] add FontStyle 'bold' and 'italic' properties to 2D text --- src/graphics/core/Batch2D.cpp | 34 +++++++++++++++++++++++ src/graphics/core/Batch2D.hpp | 7 +++++ src/graphics/core/Font.cpp | 52 +++++++++++++++++++++-------------- src/graphics/core/Font.hpp | 8 +++--- 4 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/graphics/core/Batch2D.cpp b/src/graphics/core/Batch2D.cpp index c4c67db2..b7ccf5ff 100644 --- a/src/graphics/core/Batch2D.cpp +++ b/src/graphics/core/Batch2D.cpp @@ -261,6 +261,24 @@ void Batch2D::rect( vertex(x+w, y+h, u+tx, v, r,g,b,a); } +void Batch2D::parallelogram( + float x, float y, float w, float h, float skew, + float u, float v, float tx, float ty, + float r, float g, float b, float a +){ + if (index + 6*B2D_VERTEX_SIZE >= capacity) { + flush(); + } + setPrimitive(DrawPrimitive::triangle); + vertex(x-skew*w, y, u, v+ty, r,g,b,a); + vertex(x+(1+skew)*w, y+h, u+tx, v, r,g,b,a); + vertex(x+skew*w, y+h, u, v, r,g,b,a); + + vertex(x-skew*w, y, u, v+ty, r,g,b,a); + vertex(x+w-skew*w, y, u+tx, v+ty, r,g,b,a); + vertex(x+(1+skew)*w, y+h, u+tx, v, r,g,b,a); +} + void Batch2D::rect( float x, float y, float w, float h, float r0, float g0, float b0, @@ -336,6 +354,22 @@ void Batch2D::sprite(float x, float y, float w, float h, int atlasRes, int index rect(x, y, w, h, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a); } +void Batch2D::sprite( + float x, + float y, + float w, + float h, + float skew, + int atlasRes, + int index, + glm::vec4 tint +) { + float scale = 1.0f / (float)atlasRes; + float u = (index % atlasRes) * scale; + float v = 1.0f - ((index / atlasRes) * scale) - scale; + parallelogram(x, y, w, h, skew, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a); +} + void Batch2D::flush() { if (index == 0) return; diff --git a/src/graphics/core/Batch2D.hpp b/src/graphics/core/Batch2D.hpp index 2877f5bd..6bfdb14d 100644 --- a/src/graphics/core/Batch2D.hpp +++ b/src/graphics/core/Batch2D.hpp @@ -45,6 +45,7 @@ public: void setRegion(UVRegion region); void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint); void sprite(float x, float y, float w, float h, int atlasRes, int index, glm::vec4 tint); + void sprite(float x, float y, float w, float h, float skew, int atlasRes, int index, glm::vec4 tint); void point(float x, float y, float r, float g, float b, float a); inline void setColor(glm::vec4 color) { @@ -79,6 +80,12 @@ public: float r, float g, float b, float a ); + void parallelogram( + float x, float y, float w, float h, float skew, + float u, float v, float tx, float ty, + float r, float g, float b, float a + ); + void rect( float x, float y, float w, float h, float r0, float g0, float b0, diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 9c40809f..c148ae72 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -52,17 +52,21 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float glyphInterval, + const FontStyle& style ) { - batch.sprite( - pos.x + offset.x * right.x, - pos.y + offset.y * right.y, - right.x / glyphInterval, - up.y, - 16, - c, - batch.getColor() - ); + for (int i = 0; i <= style.bold; i++) { + batch.sprite( + pos.x + (offset.x + i / (right.x/glyphInterval/2.0f)) * right.x, + pos.y + offset.y * right.y, + right.x / glyphInterval, + up.y, + -0.2f * style.italic, + 16, + c, + batch.getColor() + ); + } } static inline void draw_glyph( @@ -72,17 +76,20 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float glyphInterval, + const FontStyle& style ) { - batch.sprite( - pos + right * offset.x + up * offset.y, - up, right / glyphInterval, - 0.5f, - 0.5f, - 16, - c, - batch.getColor() - ); + for (int i = 0; i <= style.bold; i++) { + batch.sprite( + pos + right * (offset.x + i) + up * offset.y, + up, right / glyphInterval, + 0.5f, + 0.5f, + 16, + c, + batch.getColor() + ); + } } template @@ -99,6 +106,9 @@ static inline void draw_text( uint next = MAX_CODEPAGES; int x = 0; int y = 0; + + FontStyle style {}; + do { for (uint c : text){ if (!font.isPrintableChar(c)) { @@ -109,7 +119,7 @@ static inline void draw_text( if (charpage == page){ batch.texture(font.getPage(charpage)); draw_glyph( - batch, pos, glm::vec2(x, y), c, right, up, glyphInterval + batch, pos, glm::vec2(x, y), c, right, up, glyphInterval, style ); } else if (charpage > page && charpage < next){ diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index deb07534..121a19a6 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -11,10 +11,10 @@ class Batch2D; class Batch3D; class Camera; -enum class FontStyle { - none, - shadow, - outline +struct FontStyle { + bool bold = false; + bool italic = false; + glm::vec4 color {1, 1, 1, 1}; }; class Font { From ce1e9f76cffc8e8076ceeb6423523a3af1af0079 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 18:04:19 +0300 Subject: [PATCH 26/56] add FontStylesScheme --- src/graphics/core/Font.cpp | 52 +++++++++++++++++----- src/graphics/core/Font.hpp | 17 ++++++- src/graphics/render/TextsRenderer.cpp | 2 + src/graphics/ui/elements/InventoryView.cpp | 4 +- src/graphics/ui/elements/Label.cpp | 10 ++++- src/graphics/ui/elements/Label.hpp | 7 +++ src/graphics/ui/elements/Plotter.cpp | 8 +++- 7 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index c148ae72..189bec14 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -1,5 +1,6 @@ #include "Font.hpp" +#include #include #include "Texture.hpp" #include "Batch2D.hpp" @@ -64,7 +65,7 @@ static inline void draw_glyph( -0.2f * style.italic, 16, c, - batch.getColor() + batch.getColor() * style.color ); } } @@ -87,7 +88,7 @@ static inline void draw_glyph( 0.5f, 16, c, - batch.getColor() + batch.getColor() * style.color ); } } @@ -100,17 +101,33 @@ static inline void draw_text( const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float glyphInterval, + const FontStylesScheme* styles ) { + static FontStylesScheme defStyles { + {{std::numeric_limits::max()}}, + }; + if (styles == nullptr) { + styles = &defStyles; + } + uint page = 0; uint next = MAX_CODEPAGES; int x = 0; int y = 0; - FontStyle style {}; - do { - for (uint c : text){ + size_t entryIndex = 0; + int styleCharsCounter = -1; + const FontStyle* style = &styles->palette.at(entryIndex); + + for (uint c : text) { + styleCharsCounter++; + if (styleCharsCounter > style->n && + entryIndex + 1 < styles->palette.size()) { + style = &styles->palette.at(++entryIndex); + styleCharsCounter = -1; + } if (!font.isPrintableChar(c)) { x++; continue; @@ -119,7 +136,14 @@ static inline void draw_text( if (charpage == page){ batch.texture(font.getPage(charpage)); draw_glyph( - batch, pos, glm::vec2(x, y), c, right, up, glyphInterval, style + batch, + pos, + glm::vec2(x, y), + c, + right, + up, + glyphInterval, + *style ); } else if (charpage > page && charpage < next){ @@ -145,20 +169,27 @@ const Texture* Font::getPage(int charpage) const { } void Font::draw( - Batch2D& batch, std::wstring_view text, int x, int y, float scale + Batch2D& batch, + std::wstring_view text, + int x, + int y, + const FontStylesScheme* styles, + float scale ) const { draw_text( *this, batch, text, glm::vec3(x, y, 0), glm::vec3(glyphInterval*scale, 0, 0), glm::vec3(0, lineHeight*scale, 0), - glyphInterval/static_cast(lineHeight) + glyphInterval/static_cast(lineHeight), + styles ); } void Font::draw( Batch3D& batch, std::wstring_view text, + const FontStylesScheme* styles, const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up @@ -167,6 +198,7 @@ void Font::draw( *this, batch, text, pos, right * static_cast(glyphInterval), up * static_cast(lineHeight), - glyphInterval/static_cast(lineHeight) + glyphInterval/static_cast(lineHeight), + styles ); } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index 121a19a6..0543065a 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -12,11 +12,16 @@ class Batch3D; class Camera; struct FontStyle { + size_t n = -1; bool bold = false; bool italic = false; glm::vec4 color {1, 1, 1, 1}; }; +struct FontStylesScheme { + std::vector palette; +}; + class Font { int lineHeight; int yoffset; @@ -45,12 +50,20 @@ public: /// @brief Check if character is visible (non-whitespace) /// @param codepoint character unicode codepoint bool isPrintableChar(uint codepoint) const; - - void draw(Batch2D& batch, std::wstring_view text, int x, int y, float scale=1) const; + + void draw( + Batch2D& batch, + std::wstring_view text, + int x, + int y, + const FontStylesScheme* styles, + float scale = 1 + ) const; void draw( Batch3D& batch, std::wstring_view text, + const FontStylesScheme* styles, const glm::vec3& pos, const glm::vec3& right={1, 0, 0}, const glm::vec3& up={0, 1, 0} diff --git a/src/graphics/render/TextsRenderer.cpp b/src/graphics/render/TextsRenderer.cpp index fa24b61b..2a7d09db 100644 --- a/src/graphics/render/TextsRenderer.cpp +++ b/src/graphics/render/TextsRenderer.cpp @@ -98,11 +98,13 @@ void TextsRenderer::renderNote( pos + xvec * (width * 0.5f * preset.scale))) { return; } + static FontStylesScheme styles {}; auto color = preset.color; batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity)); font.draw( batch, text, + &styles, pos - xvec * (width * 0.5f) * preset.scale, xvec * preset.scale, yvec * preset.scale diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 78751cea..04e2c28b 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -194,9 +194,9 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) { int y = pos.y+slotSize-16; batch->setColor({0, 0, 0, 1.0f}); - font->draw(*batch, text, x+1, y+1); + font->draw(*batch, text, x+1, y+1, nullptr); batch->setColor(glm::vec4(1.0f)); - font->draw(*batch, text, x, y); + font->draw(*batch, text, x, y, nullptr); } } diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index c356f13b..c1a4dd0d 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -66,6 +66,8 @@ Label::Label(const std::wstring& text, std::string fontName) cache.update(this->text, multiline, textWrap); } +Label::~Label() = default; + glm::vec2 Label::calcSize() { auto font = cache.font; uint lineHeight = font->getLineHeight(); @@ -201,10 +203,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) { if (i < cache.lines.size()-1) { view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset); } - font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight); + font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight, styles.get()); } } else { - font->draw(*batch, text, pos.x, pos.y); + font->draw(*batch, text, pos.x, pos.y, styles.get()); } } @@ -239,3 +241,7 @@ void Label::setTextWrapping(bool flag) { bool Label::isTextWrapping() const { return textWrap; } + +void Label::setStyles(std::unique_ptr styles) { + this->styles = std::move(styles); +} diff --git a/src/graphics/ui/elements/Label.hpp b/src/graphics/ui/elements/Label.hpp index 4aca8a7a..f2101147 100644 --- a/src/graphics/ui/elements/Label.hpp +++ b/src/graphics/ui/elements/Label.hpp @@ -3,6 +3,7 @@ #include "UINode.hpp" class Font; +struct FontStylesScheme; namespace gui { struct LineScheme { @@ -51,10 +52,14 @@ namespace gui { /// @brief Auto resize label to fit text bool autoresize = false; + + std::unique_ptr styles; public: Label(const std::string& text, std::string fontName="normal"); Label(const std::wstring& text, std::string fontName="normal"); + virtual ~Label(); + virtual void setText(const std::wstring& text); const std::wstring& getText() const; @@ -107,5 +112,7 @@ namespace gui { virtual void setTextWrapping(bool flag); virtual bool isTextWrapping() const; + + virtual void setStyles(std::unique_ptr styles); }; } diff --git a/src/graphics/ui/elements/Plotter.cpp b/src/graphics/ui/elements/Plotter.cpp index 293d84b5..d5d906e6 100644 --- a/src/graphics/ui/elements/Plotter.cpp +++ b/src/graphics/ui/elements/Plotter.cpp @@ -47,6 +47,12 @@ void Plotter::draw(const DrawContext* pctx, Assets* assets) { batch->setColor({1,1,1,0.2f}); string = util::to_wstring(y / multiplier, 3); } - font->draw(*batch, string, pos.x+dmwidth+2, pos.y+dmheight-y-labelsInterval); + font->draw( + *batch, + string, + pos.x + dmwidth + 2, + pos.y + dmheight - y - labelsInterval, + nullptr + ); } } From ed3865964b78f2b38cc5f7c1050f7c75df74f318 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 22:13:17 +0300 Subject: [PATCH 27/56] add syntax highlighting (WIP) --- res/layouts/console.xml | 3 +- src/coders/commons.cpp | 6 +- src/coders/commons.hpp | 2 +- src/coders/lua_parsing.cpp | 24 +++++--- src/coders/lua_parsing.hpp | 2 +- src/devtools/syntax_highlighting.cpp | 72 ++++++++++++++++++++++ src/devtools/syntax_highlighting.hpp | 12 ++++ src/graphics/core/Font.cpp | 37 ++++++----- src/graphics/core/Font.hpp | 4 +- src/graphics/render/TextsRenderer.cpp | 4 +- src/graphics/ui/elements/InventoryView.cpp | 4 +- src/graphics/ui/elements/Label.cpp | 4 +- src/graphics/ui/elements/Plotter.cpp | 3 +- src/graphics/ui/elements/TextBox.cpp | 25 +++++++- src/graphics/ui/elements/TextBox.hpp | 6 ++ src/graphics/ui/gui_xml.cpp | 3 + 16 files changed, 168 insertions(+), 43 deletions(-) create mode 100644 src/devtools/syntax_highlighting.cpp create mode 100644 src/devtools/syntax_highlighting.hpp diff --git a/res/layouts/console.xml b/res/layouts/console.xml index c367545c..3f7331ee 100644 --- a/res/layouts/console.xml +++ b/res/layouts/console.xml @@ -32,10 +32,9 @@ autoresize='true' margin='0' padding='5' - editable='false' multiline='true' line-numbers='true' - text-color="#FFFFFFA0" + syntax='lua' size-func="gui.get_viewport()[1]-350,40" gravity="top-left" text-wrap='false' diff --git a/src/coders/commons.cpp b/src/coders/commons.cpp index 74fb87f5..cd9a2d4c 100644 --- a/src/coders/commons.cpp +++ b/src/coders/commons.cpp @@ -214,10 +214,14 @@ std::string_view BasicParser::readUntil(char c) { return source.substr(start, pos - start); } -std::string_view BasicParser::readUntil(std::string_view s) { +std::string_view BasicParser::readUntil(std::string_view s, bool nothrow) { int start = pos; size_t found = source.find(s, pos); if (found == std::string::npos) { + if (nothrow) { + pos = source.size(); + return source.substr(start); + } throw error(util::quote(std::string(s))+" expected"); } skip(found - pos); diff --git a/src/coders/commons.hpp b/src/coders/commons.hpp index c01601cb..9251d57d 100644 --- a/src/coders/commons.hpp +++ b/src/coders/commons.hpp @@ -105,7 +105,7 @@ protected: parsing_error error(const std::string& message); public: std::string_view readUntil(char c); - std::string_view readUntil(std::string_view s); + std::string_view readUntil(std::string_view s, bool nothrow); std::string_view readUntilWhitespace(); std::string_view readUntilEOL(); std::string parseName(); diff --git a/src/coders/lua_parsing.cpp b/src/coders/lua_parsing.cpp index f3ca21ef..e4b3c089 100644 --- a/src/coders/lua_parsing.cpp +++ b/src/coders/lua_parsing.cpp @@ -119,24 +119,28 @@ public: ); continue; } else if (is_digit(c)) { - auto value = parseNumber(1); + dv::value value; + auto tag = TokenTag::UNEXPECTED; + try { + value = parseNumber(1); + tag = value.isInteger() ? TokenTag::INTEGER + : TokenTag::NUMBER; + } catch (const parsing_error& err) {} + auto literal = source.substr(start.pos, pos - start.pos); - emitToken( - value.isInteger() ? TokenTag::INTEGER : TokenTag::NUMBER, - std::string(literal), - start - ); + emitToken(tag, std::string(literal), start); continue; } switch (c) { case '(': case '[': case '{': if (isNext("[==[")) { - readUntil("]==]"); + auto string = readUntil("]==]", true); skip(4); + emitToken(TokenTag::COMMENT, std::string(string)+"]==]", start); continue; } else if (isNext("[[")) { skip(2); - auto string = readUntil("]]"); + auto string = readUntil("]]", true); skip(2); emitToken(TokenTag::STRING, std::string(string), start); continue; @@ -154,7 +158,7 @@ public: continue; case '\'': case '"': { skip(1); - auto string = parseString(c); + auto string = parseString(c, false); emitToken(TokenTag::STRING, std::move(string), start); continue; } @@ -163,6 +167,8 @@ public: if (is_lua_operator_start(c)) { auto text = parseOperator(); if (text == "--") { + auto string = readUntilEOL(); + emitToken(TokenTag::COMMENT, std::string(string), start); skipLine(); continue; } diff --git a/src/coders/lua_parsing.hpp b/src/coders/lua_parsing.hpp index 68cc385a..1578b7fa 100644 --- a/src/coders/lua_parsing.hpp +++ b/src/coders/lua_parsing.hpp @@ -12,7 +12,7 @@ namespace lua { enum class TokenTag { KEYWORD, NAME, INTEGER, NUMBER, OPEN_BRACKET, CLOSE_BRACKET, STRING, - OPERATOR, COMMA, SEMICOLON, UNEXPECTED + OPERATOR, COMMA, SEMICOLON, UNEXPECTED, COMMENT }; struct Token { diff --git a/src/devtools/syntax_highlighting.cpp b/src/devtools/syntax_highlighting.cpp new file mode 100644 index 00000000..8442229e --- /dev/null +++ b/src/devtools/syntax_highlighting.cpp @@ -0,0 +1,72 @@ +#include "syntax_highlighting.hpp" + +#include "coders/commons.hpp" +#include "coders/lua_parsing.hpp" +#include "graphics/core/Font.hpp" + +using namespace devtools; + +static std::unique_ptr build_styles( + const std::vector& tokens +) { + FontStylesScheme styles { + { + {false, false, glm::vec4(0.8f, 0.8f, 0.8f, 1)}, // default + {true, false, glm::vec4(0.9, 0.6f, 0.4f, 1)}, // keyword + {false, false, glm::vec4(0.4, 0.8f, 0.5f, 1)}, // string + {false, false, glm::vec4(0.3, 0.3f, 0.3f, 1)}, // comment + {false, false, glm::vec4(0.4, 0.45f, 0.5f, 1)}, // self + {true, false, glm::vec4(1.0f, 0.2f, 0.1f, 1)}, // unexpected + }, + {} + }; + size_t offset = 0; + for (int i = 0; i < tokens.size(); i++) { + const auto& token = tokens.at(i); + if (token.tag != lua::TokenTag::KEYWORD && + token.tag != lua::TokenTag::STRING && + token.tag != lua::TokenTag::INTEGER && + token.tag != lua::TokenTag::NUMBER && + token.tag != lua::TokenTag::COMMENT && + token.tag != lua::TokenTag::UNEXPECTED) { + continue; + } + if (token.start.pos > offset) { + int n = token.start.pos - offset; + styles.map.insert(styles.map.end(), token.start.pos - offset, 0); + } + offset = token.end.pos; + int styleIndex; + switch (token.tag) { + case lua::TokenTag::KEYWORD: styleIndex = 1; break; + case lua::TokenTag::STRING: + case lua::TokenTag::INTEGER: + case lua::TokenTag::NUMBER: styleIndex = 2; break; + case lua::TokenTag::COMMENT: styleIndex = 3; break; + case lua::TokenTag::UNEXPECTED: styleIndex = 5; break; + default: + styleIndex = 0; + break; + } + styles.map.insert( + styles.map.end(), token.end.pos - token.start.pos, styleIndex + ); + } + styles.map.push_back(0); + return std::make_unique(std::move(styles)); +} + +std::unique_ptr devtools::syntax_highlight( + const std::string& lang, std::string_view source +) { + try { + if (lang == "lua") { + auto tokens = lua::tokenize("", source); + return build_styles(tokens); + } else { + return nullptr; + } + } catch (const parsing_error& err) { + return nullptr; + } +} diff --git a/src/devtools/syntax_highlighting.hpp b/src/devtools/syntax_highlighting.hpp new file mode 100644 index 00000000..c2f33e45 --- /dev/null +++ b/src/devtools/syntax_highlighting.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +struct FontStylesScheme; + +namespace devtools { + std::unique_ptr syntax_highlight( + const std::string& lang, std::string_view source + ); +} diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 189bec14..d3a6caf6 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -62,7 +62,7 @@ static inline void draw_glyph( pos.y + offset.y * right.y, right.x / glyphInterval, up.y, - -0.2f * style.italic, + -0.15f * style.italic, 16, c, batch.getColor() * style.color @@ -102,11 +102,11 @@ static inline void draw_text( const glm::vec3& right, const glm::vec3& up, float glyphInterval, - const FontStylesScheme* styles + const FontStylesScheme* styles, + size_t styleMapOffset ) { - static FontStylesScheme defStyles { - {{std::numeric_limits::max()}}, - }; + static FontStylesScheme defStyles {{{}}, {0}}; + if (styles == nullptr) { styles = &defStyles; } @@ -117,17 +117,12 @@ static inline void draw_text( int y = 0; do { - size_t entryIndex = 0; - int styleCharsCounter = -1; - const FontStyle* style = &styles->palette.at(entryIndex); - - for (uint c : text) { - styleCharsCounter++; - if (styleCharsCounter > style->n && - entryIndex + 1 < styles->palette.size()) { - style = &styles->palette.at(++entryIndex); - styleCharsCounter = -1; - } + for (size_t i = 0; i < text.length(); i++) { + uint c = text[i]; + size_t styleIndex = styles->map.at( + std::min(styles->map.size() - 1, i + styleMapOffset) + ); + const FontStyle& style = styles->palette.at(styleIndex); if (!font.isPrintableChar(c)) { x++; continue; @@ -143,7 +138,7 @@ static inline void draw_text( right, up, glyphInterval, - *style + style ); } else if (charpage > page && charpage < next){ @@ -174,6 +169,7 @@ void Font::draw( int x, int y, const FontStylesScheme* styles, + size_t styleMapOffset, float scale ) const { draw_text( @@ -182,7 +178,8 @@ void Font::draw( glm::vec3(glyphInterval*scale, 0, 0), glm::vec3(0, lineHeight*scale, 0), glyphInterval/static_cast(lineHeight), - styles + styles, + styleMapOffset ); } @@ -190,6 +187,7 @@ void Font::draw( Batch3D& batch, std::wstring_view text, const FontStylesScheme* styles, + size_t styleMapOffset, const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up @@ -199,6 +197,7 @@ void Font::draw( right * static_cast(glyphInterval), up * static_cast(lineHeight), glyphInterval/static_cast(lineHeight), - styles + styles, + styleMapOffset ); } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index 0543065a..6721be98 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -12,7 +12,6 @@ class Batch3D; class Camera; struct FontStyle { - size_t n = -1; bool bold = false; bool italic = false; glm::vec4 color {1, 1, 1, 1}; @@ -20,6 +19,7 @@ struct FontStyle { struct FontStylesScheme { std::vector palette; + std::vector map; }; class Font { @@ -57,6 +57,7 @@ public: int x, int y, const FontStylesScheme* styles, + size_t styleMapOffset, float scale = 1 ) const; @@ -64,6 +65,7 @@ public: Batch3D& batch, std::wstring_view text, const FontStylesScheme* styles, + size_t styleMapOffset, const glm::vec3& pos, const glm::vec3& right={1, 0, 0}, const glm::vec3& up={0, 1, 0} diff --git a/src/graphics/render/TextsRenderer.cpp b/src/graphics/render/TextsRenderer.cpp index 2a7d09db..32681ce5 100644 --- a/src/graphics/render/TextsRenderer.cpp +++ b/src/graphics/render/TextsRenderer.cpp @@ -98,13 +98,13 @@ void TextsRenderer::renderNote( pos + xvec * (width * 0.5f * preset.scale))) { return; } - static FontStylesScheme styles {}; auto color = preset.color; batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity)); font.draw( batch, text, - &styles, + nullptr, + 0, pos - xvec * (width * 0.5f) * preset.scale, xvec * preset.scale, yvec * preset.scale diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 04e2c28b..2c763ca4 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -194,9 +194,9 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) { int y = pos.y+slotSize-16; batch->setColor({0, 0, 0, 1.0f}); - font->draw(*batch, text, x+1, y+1, nullptr); + font->draw(*batch, text, x+1, y+1, nullptr, 0); batch->setColor(glm::vec4(1.0f)); - font->draw(*batch, text, x, y, nullptr); + font->draw(*batch, text, x, y, nullptr, 0); } } diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index c1a4dd0d..87346db5 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -203,10 +203,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) { if (i < cache.lines.size()-1) { view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset); } - font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight, styles.get()); + font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight, styles.get(), offset); } } else { - font->draw(*batch, text, pos.x, pos.y, styles.get()); + font->draw(*batch, text, pos.x, pos.y, styles.get(), 0); } } diff --git a/src/graphics/ui/elements/Plotter.cpp b/src/graphics/ui/elements/Plotter.cpp index d5d906e6..122734a3 100644 --- a/src/graphics/ui/elements/Plotter.cpp +++ b/src/graphics/ui/elements/Plotter.cpp @@ -52,7 +52,8 @@ void Plotter::draw(const DrawContext* pctx, Assets* assets) { string, pos.x + dmwidth + 2, pos.y + dmheight - y - labelsInterval, - nullptr + nullptr, + 0 ); } } diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 6a54d682..3403e813 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -5,6 +5,7 @@ #include #include "Label.hpp" +#include "devtools/syntax_highlighting.hpp" #include "graphics/core/DrawContext.hpp" #include "graphics/core/Batch2D.hpp" #include "graphics/core/Font.hpp" @@ -65,11 +66,10 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) { lcoord.y -= 2; auto batch = pctx->getBatch2D(); batch->texture(nullptr); + batch->setColor(glm::vec4(1.0f)); if (editable && int((Window::time() - caretLastMove) * 2) % 2 == 0) { uint line = label->getLineByTextIndex(caret); uint lcaret = caret - label->getTextLineOffset(line); - batch->setColor(glm::vec4(1.0f)); - int width = font->calcWidth(input, lcaret); batch->rect(lcoord.x + width, lcoord.y+label->getLineYOffset(line), 2, lineHeight); } @@ -529,10 +529,21 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) { } } +void TextBox::refreshSyntax() { + if (!syntax.empty()) { + if (auto styles = devtools::syntax_highlight( + syntax, util::wstr2str_utf8(input) + )) { + label->setStyles(std::move(styles)); + } + } +} + void TextBox::onInput() { if (subconsumer) { subconsumer(input); } + refreshSyntax(); } void TextBox::performEditingKeyboardEvents(keycode key) { @@ -710,6 +721,7 @@ const std::wstring& TextBox::getText() const { void TextBox::setText(const std::wstring& value) { this->input = value; input.erase(std::remove(input.begin(), input.end(), '\r'), input.end()); + refreshSyntax(); } const std::wstring& TextBox::getPlaceholder() const { @@ -789,3 +801,12 @@ void TextBox::setShowLineNumbers(bool flag) { bool TextBox::isShowLineNumbers() const { return showLineNumbers; } + +void TextBox::setSyntax(const std::string& lang) { + syntax = lang; + if (syntax.empty()) { + label->setStyles(nullptr); + } else { + refreshSyntax(); + } +} diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index d2c4fd8c..c23cf740 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -57,6 +57,8 @@ namespace gui { bool autoresize = false; bool showLineNumbers = false; + std::string syntax; + void stepLeft(bool shiftPressed, bool breakSelection); void stepRight(bool shiftPressed, bool breakSelection); void stepDefaultDown(bool shiftPressed, bool breakSelection); @@ -84,6 +86,8 @@ namespace gui { void refreshLabel(); void onInput(); + + void refreshSyntax(); public: TextBox( std::wstring placeholder, @@ -219,5 +223,7 @@ namespace gui { virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; virtual void setOnUpPressed(const runnable &callback); virtual void setOnDownPressed(const runnable &callback); + + virtual void setSyntax(const std::string& lang); }; } diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index c25b65b2..0c721524 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -357,6 +357,9 @@ static std::shared_ptr readTextBox(UiXmlReader& reader, const xml::xmlel } textbox->setText(text); + if (element->has("syntax")) { + textbox->setSyntax(element->attr("syntax").getText()); + } if (element->has("multiline")) { textbox->setMultiline(element->attr("multiline").asBool()); } From dbd27d4423a8b8c9dcf2c6e3c64b9786bc7656da Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 23:03:36 +0300 Subject: [PATCH 28/56] add scrollbar (WIP) --- src/graphics/ui/elements/Container.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index fdd0bc02..f5a6a533 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -95,6 +95,19 @@ void Container::draw(const DrawContext* pctx, Assets* assets) { if (node->isVisible()) node->draw(pctx, assets); } + + int diff = (actualLength-size.y); + if (scrollable && diff > 0) { + int w = 10; + int h = glm::max(size.y / actualLength * size.y, w / 2.0f); + batch->untexture(); + batch->setColor(glm::vec4(1, 1, 1, 0.5f)); + batch->rect( + pos.x + size.x - w, + pos.y - scroll / static_cast(diff) * (size.y - h), + w, h + ); + } batch->flush(); } } From 2fa78b7b2178799cdcff644e4ae414086e526ff7 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 23:32:22 +0300 Subject: [PATCH 29/56] fix random fatal error in socket:recv --- src/logic/scripting/lua/libs/libnetwork.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 61d44de7..dc752710 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -101,7 +101,8 @@ static int l_recv(lua::State* L) { if (connection == nullptr) { return 0; } - util::Buffer buffer(glm::min(length, connection->available())); + length = glm::min(length, connection->available()); + util::Buffer buffer(length); int size = connection->recv(buffer.data(), length); if (size == -1) { From d0fbbeecbe12aeaeb696ee4957dcf96eaf72fe42 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Dec 2024 23:32:22 +0300 Subject: [PATCH 30/56] fix random fatal error in socket:recv --- src/logic/scripting/lua/libs/libnetwork.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 61d44de7..dc752710 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -101,7 +101,8 @@ static int l_recv(lua::State* L) { if (connection == nullptr) { return 0; } - util::Buffer buffer(glm::min(length, connection->available())); + length = glm::min(length, connection->available()); + util::Buffer buffer(length); int size = connection->recv(buffer.data(), length); if (size == -1) { From bad2b44c968af419fb78ffa0e17f84f111030cfa Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 5 Dec 2024 14:42:33 +0300 Subject: [PATCH 31/56] fix incorrect virtual inventory id in scripting --- src/items/Inventories.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/items/Inventories.cpp b/src/items/Inventories.cpp index d3af607d..4d2baa36 100644 --- a/src/items/Inventories.cpp +++ b/src/items/Inventories.cpp @@ -20,7 +20,9 @@ std::shared_ptr Inventories::create(size_t size) { std::shared_ptr Inventories::createVirtual(size_t size) { int64_t id; do { - id = -std::max(1LL, std::llabs(random.rand64())); + // lua does not support long integers because Number is floating-point + // type. Changing int_consumer to use 64 bit integer does not change anything + id = -std::max(1LL, std::llabs(random.rand64() % 1000'000'000)); } while (map.find(id) != map.end()); auto inv = std::make_shared(id, size); From b65ba61f9a978e72ef015e938de35b2da2b4d374 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 5 Dec 2024 14:43:24 +0300 Subject: [PATCH 32/56] make scrollbar interactive --- src/frontend/hud.cpp | 8 ++-- src/graphics/ui/elements/Container.cpp | 43 +++++++++++++++++++--- src/graphics/ui/elements/Container.hpp | 9 +++++ src/graphics/ui/elements/InventoryView.cpp | 10 ++--- src/graphics/ui/elements/InventoryView.hpp | 2 +- src/graphics/ui/elements/TextBox.cpp | 9 ++++- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 30659969..21111e18 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -124,7 +124,7 @@ std::shared_ptr Hud::createContentAccess() { }); InventoryBuilder builder; - builder.addGrid(8, itemsCount-1, glm::vec2(), 8, true, slotLayout); + builder.addGrid(8, itemsCount-1, glm::vec2(), glm::vec4(8, 8, 12, 8), true, slotLayout); auto view = builder.build(); view->bind(accessInventory, content); view->setMargin(glm::vec4()); @@ -137,7 +137,7 @@ std::shared_ptr Hud::createHotbar() { SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr); InventoryBuilder builder; - builder.addGrid(10, 10, glm::vec2(), 4, true, slotLayout); + builder.addGrid(10, 10, glm::vec2(), glm::vec4(4), true, slotLayout); auto view = builder.build(); view->setId("hud.hotbar"); view->setOrigin(glm::vec2(view->getSize().x/2, 0)); @@ -346,9 +346,9 @@ void Hud::update(bool visible) { element.getNode()->setVisible(visible); } - glm::vec2 invSize = contentAccessPanel->getSize(); + glm::vec2 caSize = contentAccessPanel->getSize(); contentAccessPanel->setVisible(inventoryView != nullptr && showContentPanel); - contentAccessPanel->setSize(glm::vec2(invSize.x, Window::height)); + contentAccessPanel->setSize(glm::vec2(caSize.x, Window::height)); contentAccess->setMinSize(glm::vec2(1, Window::height)); hotbarView->setVisible(visible && !(secondUI && !inventoryView)); diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index f5a6a533..86914077 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -23,6 +23,11 @@ std::shared_ptr Container::getAt(glm::vec2 pos, std::shared_ptr } if (!isInside(pos)) return nullptr; + int diff = (actualLength-size.y); + if (scrollable && diff > 0 && pos.x > calcPos().x + getSize().x - scrollBarWidth) { + return UINode::getAt(pos, self); + } + for (int i = nodes.size()-1; i >= 0; i--) { auto& node = nodes[i]; if (!node->isVisible()) @@ -35,6 +40,35 @@ std::shared_ptr Container::getAt(glm::vec2 pos, std::shared_ptr return UINode::getAt(pos, self); } +void Container::mouseMove(GUI* gui, int x, int y) { + UINode::mouseMove(gui, x, y); + if (!scrollable) { + return; + } + auto pos = calcPos(); + x -= pos.x; + y -= pos.y; + if (prevScrollY == -1) { + if (x >= size.x - scrollBarWidth) { + prevScrollY = y; + } + return; + } + int diff = (actualLength-size.y); + if (diff > 0) { + scroll -= (y - prevScrollY) / static_cast(size.y) * actualLength; + scroll = -glm::min( + glm::max(static_cast(-scroll), 0.0f), actualLength - size.y + ); + } + prevScrollY = y; +} + +void Container::mouseRelease(GUI* gui, int x, int y) { + UINode::mouseRelease(gui, x, y); + prevScrollY = -1; +} + void Container::act(float delta) { for (const auto& node : nodes) { if (node->isVisible()) { @@ -98,14 +132,13 @@ void Container::draw(const DrawContext* pctx, Assets* assets) { int diff = (actualLength-size.y); if (scrollable && diff > 0) { - int w = 10; - int h = glm::max(size.y / actualLength * size.y, w / 2.0f); + int h = glm::max(size.y / actualLength * size.y, scrollBarWidth / 2.0f); batch->untexture(); - batch->setColor(glm::vec4(1, 1, 1, 0.5f)); + batch->setColor(glm::vec4(1, 1, 1, 0.3f)); batch->rect( - pos.x + size.x - w, + pos.x + size.x - scrollBarWidth, pos.y - scroll / static_cast(diff) * (size.y - h), - w, h + scrollBarWidth, h ); } batch->flush(); diff --git a/src/graphics/ui/elements/Container.hpp b/src/graphics/ui/elements/Container.hpp index bfe40ab5..420a7e55 100644 --- a/src/graphics/ui/elements/Container.hpp +++ b/src/graphics/ui/elements/Container.hpp @@ -7,13 +7,19 @@ namespace gui { class Container : public UINode { + int prevScrollY = -1; protected: std::vector> nodes; std::vector intervalEvents; int scroll = 0; int scrollStep = 40; + int scrollBarWidth = 10; int actualLength = 0; bool scrollable = true; + + bool isScrolling() { + return prevScrollY != -1; + } public: Container(glm::vec2 size); virtual ~Container(); @@ -36,6 +42,9 @@ namespace gui { virtual void setScrollStep(int step); virtual void refresh() override; + virtual void mouseMove(GUI*, int x, int y) override; + virtual void mouseRelease(GUI*, int x, int y) override; + const std::vector>& getNodes() const; }; } diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 2c763ca4..217de57f 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -54,7 +54,7 @@ InventoryBuilder::InventoryBuilder() { void InventoryBuilder::addGrid( int cols, int count, glm::vec2 pos, - int padding, + glm::vec4 padding, bool addpanel, const SlotLayout& slotLayout ) { @@ -63,8 +63,8 @@ void InventoryBuilder::addGrid( int rows = ceildiv(count, cols); - uint width = cols * (slotSize + interval) - interval + padding*2; - uint height = rows * (slotSize + interval) - interval + padding*2; + uint width = cols * (slotSize + interval) - interval + padding.x + padding.z; + uint height = rows * (slotSize + interval) - interval + padding.y + padding.w; glm::vec2 vsize = view->getSize(); if (pos.x + width > vsize.x) { @@ -87,8 +87,8 @@ void InventoryBuilder::addGrid( break; } glm::vec2 position ( - col * (slotSize + interval) + padding, - row * (slotSize + interval) + padding + col * (slotSize + interval) + padding.x, + row * (slotSize + interval) + padding.y ); auto builtSlot = slotLayout; builtSlot.index = row * cols + col; diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp index e37e6681..920636cb 100644 --- a/src/graphics/ui/elements/InventoryView.hpp +++ b/src/graphics/ui/elements/InventoryView.hpp @@ -136,7 +136,7 @@ namespace gui { void addGrid( int cols, int count, glm::vec2 pos, - int padding, + glm::vec4 padding, bool addpanel, const SlotLayout& slotLayout ); diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 3403e813..4bd72fff 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -74,6 +74,9 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) { batch->rect(lcoord.x + width, lcoord.y+label->getLineYOffset(line), 2, lineHeight); } if (selectionStart != selectionEnd) { + auto selectionCtx = subctx.sub(batch); + selectionCtx.setBlendMode(BlendMode::addition); + uint startLine = label->getLineByTextIndex(selectionStart); uint endLine = label->getLineByTextIndex(selectionEnd); @@ -433,7 +436,11 @@ void TextBox::click(GUI*, int x, int y) { selectionOrigin = index; } -void TextBox::mouseMove(GUI*, int x, int y) { +void TextBox::mouseMove(GUI* gui, int x, int y) { + Container::mouseMove(gui, x, y); + if (isScrolling()) { + return; + } ptrdiff_t index = calcIndexAt(x, y); setCaret(index); extendSelection(index); From f4b80b17405ad9eab3dbcb3901a22c77f5f37b07 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 5 Dec 2024 14:42:33 +0300 Subject: [PATCH 33/56] fix incorrect virtual inventory id in scripting --- src/items/Inventories.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/items/Inventories.cpp b/src/items/Inventories.cpp index d3af607d..4d2baa36 100644 --- a/src/items/Inventories.cpp +++ b/src/items/Inventories.cpp @@ -20,7 +20,9 @@ std::shared_ptr Inventories::create(size_t size) { std::shared_ptr Inventories::createVirtual(size_t size) { int64_t id; do { - id = -std::max(1LL, std::llabs(random.rand64())); + // lua does not support long integers because Number is floating-point + // type. Changing int_consumer to use 64 bit integer does not change anything + id = -std::max(1LL, std::llabs(random.rand64() % 1000'000'000)); } while (map.find(id) != map.end()); auto inv = std::make_shared(id, size); From 04b6b6b5469dfc7338873441ab30e398bd225e4e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 5 Dec 2024 19:18:53 +0300 Subject: [PATCH 34/56] minor refactor --- src/engine.cpp | 2 +- src/frontend/hud.hpp | 12 ++-- src/graphics/ui/GUI.cpp | 8 +-- src/graphics/ui/GUI.hpp | 2 +- src/graphics/ui/elements/Button.cpp | 6 +- src/graphics/ui/elements/Button.hpp | 6 +- src/graphics/ui/elements/CheckBox.cpp | 4 +- src/graphics/ui/elements/CheckBox.hpp | 2 +- src/graphics/ui/elements/Container.cpp | 21 ++++--- src/graphics/ui/elements/Container.hpp | 10 ++-- src/graphics/ui/elements/Image.cpp | 8 +-- src/graphics/ui/elements/Image.hpp | 2 +- src/graphics/ui/elements/InputBindBox.cpp | 8 +-- src/graphics/ui/elements/InputBindBox.hpp | 5 +- src/graphics/ui/elements/InventoryView.cpp | 10 ++-- src/graphics/ui/elements/InventoryView.hpp | 2 +- src/graphics/ui/elements/Label.cpp | 6 +- src/graphics/ui/elements/Label.hpp | 2 +- src/graphics/ui/elements/Menu.hpp | 4 +- src/graphics/ui/elements/Panel.hpp | 2 +- src/graphics/ui/elements/Plotter.cpp | 6 +- src/graphics/ui/elements/Plotter.hpp | 2 +- src/graphics/ui/elements/TextBox.cpp | 67 ++++++++++++++++------ src/graphics/ui/elements/TextBox.hpp | 8 ++- src/graphics/ui/elements/TrackBar.cpp | 4 +- src/graphics/ui/elements/TrackBar.hpp | 2 +- src/graphics/ui/elements/UINode.cpp | 4 +- src/graphics/ui/elements/UINode.hpp | 4 +- src/presets/ParticlesPreset.hpp | 2 +- 29 files changed, 130 insertions(+), 91 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index 31db4537..129dc68d 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -206,7 +206,7 @@ void Engine::renderFrame(Batch2D& batch) { Viewport viewport(Window::width, Window::height); DrawContext ctx(nullptr, viewport, &batch); - gui->draw(&ctx, assets.get()); + gui->draw(ctx, *assets); } void Engine::processPostRunnables() { diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index 580ab54d..5594664a 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -95,16 +95,16 @@ class Hud : public util::ObjectsKeeper { /// @brief Inventories interaction agent (grabbed item) std::shared_ptr exchangeSlot; /// @brief Exchange slot inventory (1 slot only) - std::shared_ptr exchangeSlotInv = nullptr; + std::shared_ptr exchangeSlotInv; /// @brief List of all controlled hud elements std::vector elements; /// @brief Player inventory view - std::shared_ptr inventoryView = nullptr; + std::shared_ptr inventoryView; /// @brief Block inventory view - std::shared_ptr blockUI = nullptr; + std::shared_ptr blockUI; /// @brief Secondary inventory view - std::shared_ptr secondInvView = nullptr; + std::shared_ptr secondInvView; /// @brief Position of the block open glm::ivec3 blockPos {}; /// @brief Id of the block open (used to detect block destruction or replacement) @@ -114,9 +114,9 @@ class Hud : public util::ObjectsKeeper { /// @brief Provide cheat controllers to the debug panel bool allowDebugCheats = true; /// @brief UI element will be dynamicly positioned near to inventory or in screen center - std::shared_ptr secondUI = nullptr; + std::shared_ptr secondUI; - std::shared_ptr debugMinimap = nullptr; + std::shared_ptr debugMinimap; std::unique_ptr debugImgWorldGen; diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 40b74a4c..38bc2257 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -197,18 +197,18 @@ void GUI::act(float delta, const Viewport& vp) { } } -void GUI::draw(const DrawContext* pctx, Assets* assets) { - auto& viewport = pctx->getViewport(); +void GUI::draw(const DrawContext& pctx, const Assets& assets) { + auto& viewport = pctx.getViewport(); glm::vec2 wsize = viewport.size(); menu->setPos((wsize - menu->getSize()) / 2.0f); uicamera->setFov(wsize.y); - auto uishader = assets->get("ui"); + auto uishader = assets.get("ui"); uishader->use(); uishader->uniformMatrix("u_projview", uicamera->getProjView()); - pctx->getBatch2D()->begin(); + pctx.getBatch2D()->begin(); container->draw(pctx, assets); } diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index b2b20bd0..c0dec649 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -94,7 +94,7 @@ namespace gui { /// @brief Draw all visible elements on main container /// @param pctx parent graphics context /// @param assets active assets storage - void draw(const DrawContext* pctx, Assets* assets); + void draw(const DrawContext& pctx, const Assets& assets); /// @brief Add element to the main container /// @param node UI element diff --git a/src/graphics/ui/elements/Button.cpp b/src/graphics/ui/elements/Button.cpp index b6a11232..dfdf864d 100644 --- a/src/graphics/ui/elements/Button.cpp +++ b/src/graphics/ui/elements/Button.cpp @@ -52,7 +52,7 @@ Button::Button( void Button::setText(std::wstring text) { if (label) { - label->setText(text); + label->setText(std::move(text)); } } @@ -77,9 +77,9 @@ void Button::refresh() { } } -void Button::drawBackground(const DrawContext* pctx, Assets*) { +void Button::drawBackground(const DrawContext& pctx, const Assets&) { glm::vec2 pos = calcPos(); - auto batch = pctx->getBatch2D(); + auto batch = pctx.getBatch2D(); batch->texture(nullptr); batch->setColor(calcColor()); batch->rect(pos.x, pos.y, size.x, size.y); diff --git a/src/graphics/ui/elements/Button.hpp b/src/graphics/ui/elements/Button.hpp index 61bfea03..39b23426 100644 --- a/src/graphics/ui/elements/Button.hpp +++ b/src/graphics/ui/elements/Button.hpp @@ -7,7 +7,7 @@ namespace gui { class Button : public Panel { protected: - std::shared_ptr