From bb15d17892d5e5f516d8f7c2f07ebadee19ef5d8 Mon Sep 17 00:00:00 2001 From: Stepanov Igor Date: Thu, 9 Jan 2025 16:32:54 +0300 Subject: [PATCH 01/21] add cmake-format.py and formating all cmake files --- .cmake-format.py | 3 ++ CMakeLists.txt | 78 +++++++++++++++++++++++++------------------ src/CMakeLists.txt | 32 +++++++++++++----- test/CMakeLists.txt | 26 ++++++--------- vctest/CMakeLists.txt | 35 ++++++++++++------- 5 files changed, 105 insertions(+), 69 deletions(-) create mode 100644 .cmake-format.py diff --git a/.cmake-format.py b/.cmake-format.py new file mode 100644 index 00000000..2a46b909 --- /dev/null +++ b/.cmake-format.py @@ -0,0 +1,3 @@ +tab_size = 4 +enable_sort = True +autosort = True diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b5c6fc8..abfd430e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,18 +8,20 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - # We use two types linking: for clang build is static (vcpkg triplet x64-windows-static) - # and for msvc build is dynamic linking (vcpkg triplet x64-windows) - # By default CMAKE_MSVC_RUNTIME_LIBRARY set by MultiThreaded$<$:Debug>DLL - if (VCPKG_TARGET_TRIPLET MATCHES "static") - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - endif() +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # We use two types linking: for clang build is static (vcpkg triplet + # x64-windows-static) and for msvc build is dynamic linking (vcpkg triplet + # x64-windows) By default CMAKE_MSVC_RUNTIME_LIBRARY set by + # MultiThreaded$<$:Debug>DLL + if(VCPKG_TARGET_TRIPLET MATCHES "static") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() endif() add_subdirectory(src) add_executable(${PROJECT_NAME} src/main.cpp) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) +target_include_directories(${PROJECT_NAME} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) if(VOXELENGINE_BUILD_APPDIR) include(${CMAKE_CURRENT_SOURCE_DIR}/dev/cmake/BuildAppdir.cmake) @@ -27,33 +29,44 @@ endif() if(MSVC) if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set(CMAKE_BUILD_TYPE + Release + CACHE STRING "Build type" FORCE) endif() - if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL "RelWithDebInfo")) - target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) + if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL + "RelWithDebInfo")) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) else() - target_compile_options(${PROJECT_NAME} PRIVATE /W4) + target_compile_options(${PROJECT_NAME} PRIVATE /W4) endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /source-charset:UTF-8 /D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} /source-charset:UTF-8 /D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR" + ) else() - target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra - # additional warnings - -Wformat-nonliteral -Wcast-align - -Wpointer-arith -Wundef - -Wwrite-strings -Wno-unused-parameter) - if (CMAKE_BUILD_TYPE MATCHES "Debug") - target_compile_options(${PROJECT_NAME} PRIVATE -Og) - endif() - if (WIN32) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") - endif() + target_compile_options( + ${PROJECT_NAME} + PRIVATE -Wall + -Wextra + # additional warnings + -Wformat-nonliteral + -Wcast-align + -Wpointer-arith + -Wundef + -Wwrite-strings + -Wno-unused-parameter) + if(CMAKE_BUILD_TYPE MATCHES "Debug") + target_compile_options(${PROJECT_NAME} PRIVATE -Og) + endif() + if(WIN32) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") + endif() endif() -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs") endif() -if (WIN32) +if(WIN32) target_link_libraries(${PROJECT_NAME} VoxelEngineSrc winmm) endif() @@ -61,14 +74,13 @@ target_link_libraries(${PROJECT_NAME} VoxelEngineSrc ${CMAKE_DL_LIBS}) # Deploy res to build dir add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/res - $/res - ) + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy_directory_if_different + ${CMAKE_CURRENT_SOURCE_DIR}/res $/res) -if (VOXELENGINE_BUILD_TESTS) +if(VOXELENGINE_BUILD_TESTS) enable_testing() add_subdirectory(test) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6350f4b8..09d3d0c8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,7 @@ add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) -if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") # specific for vcpkg find_package(OpenAL CONFIG REQUIRED) set(OPENAL_LIBRARY OpenAL::OpenAL) @@ -20,17 +20,19 @@ endif() find_package(ZLIB REQUIRED) find_package(PNG REQUIRED) find_package(CURL REQUIRED) -if (NOT APPLE) +if(NOT APPLE) find_package(EnTT REQUIRED) endif() set(LIBS "") -if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - # Use directly linking to lib instead PkgConfig (because pkg-config dont install on windows as default) - # TODO: Do it with findLua. - if (MSVC) - set(LUA_INCLUDE_DIR "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit") +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # Use directly linking to lib instead PkgConfig (because pkg-config dont + # install on windows as default) TODO: Do it with findLua. + if(MSVC) + set(LUA_INCLUDE_DIR + "$ENV{VCPKG_ROOT}/packages/luajit_${VCPKG_TARGET_TRIPLET}/include/luajit" + ) find_package(Lua REQUIRED) else() # Used for mingw-clang cross compiling from msys2 @@ -49,7 +51,7 @@ elseif(APPLE) set(LUA_LIBRARIES "/opt/homebrew/lib/libluajit-5.1.a") message(STATUS "LUA Libraries: ${LUA_LIBRARIES}") message(STATUS "LUA Include Dir: ${LUA_INCLUDE_DIR}") - + set(VORBISLIB ${VORBIS_LDFLAGS}) message(STATUS "Vorbis Lib: ${VORBIS_LDFLAGS}") else() @@ -70,4 +72,16 @@ endif() include_directories(${LUA_INCLUDE_DIR}) include_directories(${CURL_INCLUDE_DIR}) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(${PROJECT_NAME} ${LIBS} glfw OpenGL::GL ${OPENAL_LIBRARY} GLEW::GLEW ZLIB::ZLIB PNG::PNG CURL::libcurl ${VORBISLIB} ${LUA_LIBRARIES} ${CMAKE_DL_LIBS}) +target_link_libraries( + ${PROJECT_NAME} + ${LIBS} + glfw + OpenGL::GL + ${OPENAL_LIBRARY} + GLEW::GLEW + ZLIB::ZLIB + PNG::PNG + CURL::libcurl + ${VORBISLIB} + ${LUA_LIBRARIES} + ${CMAKE_DL_LIBS}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0597d6e4..df2d1e17 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,23 +8,19 @@ find_package(GTest) add_executable(${PROJECT_NAME} ${SOURCES}) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) -target_link_libraries( - ${PROJECT_NAME} - VoxelEngineSrc - GTest::gtest_main -) +target_include_directories(${PROJECT_NAME} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) +target_link_libraries(${PROJECT_NAME} VoxelEngineSrc GTest::gtest_main) -# HACK: copy res to test/ folder for fixing problem compatibility MultiConfig and non -# MultiConfig builds. Delete in future and use only root res folder -# Also this resolve problem with ctests, because it set cwd to CMAKE_CURRENT_BINARY_DIR +# HACK: copy res to test/ folder for fixing problem compatibility MultiConfig +# and non MultiConfig builds. Delete in future and use only root res folder Also +# this resolve problem with ctests, because it set cwd to +# CMAKE_CURRENT_BINARY_DIR add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different - ${CMAKE_SOURCE_DIR}/res - ${CMAKE_CURRENT_BINARY_DIR}/res - ) + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different + ${CMAKE_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/res) include(GoogleTest) gtest_discover_tests(${PROJECT_NAME}) diff --git a/vctest/CMakeLists.txt b/vctest/CMakeLists.txt index 6c1a3843..916eef31 100644 --- a/vctest/CMakeLists.txt +++ b/vctest/CMakeLists.txt @@ -8,24 +8,35 @@ add_executable(${PROJECT_NAME} ${SOURCES}) if(MSVC) if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set(CMAKE_BUILD_TYPE + Release + CACHE STRING "Build type" FORCE) endif() - if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL "RelWithDebInfo")) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Release>") - target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) + if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL + "RelWithDebInfo")) + set(CMAKE_MSVC_RUNTIME_LIBRARY + "MultiThreaded$<$:Release>") + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) else() - target_compile_options(${PROJECT_NAME} PRIVATE /W4) + target_compile_options(${PROJECT_NAME} PRIVATE /W4) endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else() - target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra - -Wformat-nonliteral -Wcast-align - -Wpointer-arith -Wundef - -Wwrite-strings -Wno-unused-parameter) + target_compile_options( + ${PROJECT_NAME} + PRIVATE -Wall + -Wextra + -Wformat-nonliteral + -Wcast-align + -Wpointer-arith + -Wundef + -Wwrite-strings + -Wno-unused-parameter) endif() -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs") endif() -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src ${CMAKE_DL_LIBS}) +target_include_directories( + ${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src ${CMAKE_DL_LIBS}) From 653d1d20d46a698ab4b78d0d7156f75d2572ae3a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 9 Jan 2025 18:53:25 +0300 Subject: [PATCH 02/21] add app.is_content_loaded() --- dev/tests/world.lua | 2 ++ doc/en/scripting/builtins/libapp.md | 6 ++++++ doc/ru/scripting/builtins/libapp.md | 6 ++++++ res/scripts/stdlib.lua | 1 + src/logic/scripting/lua/libs/libcore.cpp | 5 +++++ 5 files changed, 20 insertions(+) diff --git a/dev/tests/world.lua b/dev/tests/world.lua index db1ffca5..cd9c21c3 100644 --- a/dev/tests/world.lua +++ b/dev/tests/world.lua @@ -5,6 +5,7 @@ app.reconfig_packs({"base"}, {}) app.new_world("demo", "2019", "core:default") assert(world.is_open()) assert(world.get_generator() == "core:default") +assert(app.is_content_loaded()) app.sleep(1) assert(world.get_total_time() > 0.0) print(world.get_total_time()) @@ -12,6 +13,7 @@ print(world.get_total_time()) -- Close app.close_world(true) assert(not world.is_open()) +assert(not app.is_content_loaded()) -- Reopen app.open_world("demo") diff --git a/doc/en/scripting/builtins/libapp.md b/doc/en/scripting/builtins/libapp.md index e3fed3d4..ffc4d923 100644 --- a/doc/en/scripting/builtins/libapp.md +++ b/doc/en/scripting/builtins/libapp.md @@ -69,6 +69,12 @@ app.config_packs( Updates the packs configuration, automatically removing unspecified ones, adding those missing in the previous configuration. Uses app.reconfig_packs. +```lua +app.is_content_loaded() -> bool +``` + +Checks if content is loaded. + ```lua app.new_world( -- world name diff --git a/doc/ru/scripting/builtins/libapp.md b/doc/ru/scripting/builtins/libapp.md index 7887bcdf..c0f3b741 100644 --- a/doc/ru/scripting/builtins/libapp.md +++ b/doc/ru/scripting/builtins/libapp.md @@ -69,6 +69,12 @@ app.config_packs( Обновляет конфигурацию паков, автоматически удаляя лишние, добавляя отсутствующие в прошлой конфигурации. Использует app.reconfig_packs. +```lua +app.is_content_loaded() -> bool +``` + +Проверяет, загружен ли контент. + ```lua app.new_world( -- название мира diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index f376e210..ad36a221 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -39,6 +39,7 @@ local function complete_app_lib(app) app.get_setting_info = core.get_setting_info app.load_content = core.load_content app.reset_content = core.reset_content + app.is_content_loaded = core.is_content_loaded function app.config_packs(packs_list) -- Check if packs are valid and add dependencies to the configuration diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 80a924c5..7946d301 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -43,6 +43,10 @@ static int l_reset_content(lua::State* L) { return 0; } +static int l_is_content_loaded(lua::State* L) { + return lua::pushboolean(L, content != nullptr); +} + /// @brief Creating new world /// @param name Name world /// @param seed Seed world @@ -258,6 +262,7 @@ const luaL_Reg corelib[] = { {"get_version", lua::wrap}, {"load_content", lua::wrap}, {"reset_content", lua::wrap}, + {"is_content_loaded", lua::wrap}, {"new_world", lua::wrap}, {"open_world", lua::wrap}, {"reopen_world", lua::wrap}, From 7b962841d6a256b3a005a7fe7c2d296ca2baed28 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Jan 2025 18:50:45 +0300 Subject: [PATCH 03/21] fix world.set_chunk_data & rid of extra memory allocations in world.get_chunk_data --- src/logic/scripting/lua/libs/libworld.cpp | 86 +++++++++++------------ 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 1acc1ad7..832f2e2e 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -7,6 +7,7 @@ #include "coders/compression.hpp" #include "coders/gzip.hpp" #include "coders/json.hpp" +#include "coders/rle.hpp" #include "engine/Engine.hpp" #include "files/engine_paths.hpp" #include "files/files.hpp" @@ -123,45 +124,44 @@ static int l_get_generator(lua::State* L) { } static int l_get_chunk_data(lua::State* L) { - int x = (int)lua::tointeger(L, 1); - int y = (int)lua::tointeger(L, 2); + int x = static_cast(lua::tointeger(L, 1)); + int y = static_cast(lua::tointeger(L, 2)); const auto& chunk = level->chunks->getChunk(x, y); if (chunk == nullptr) { lua::pushnil(L); return 0; } - bool compress = false; + bool compress = true; if (lua::gettop(L) >= 3) { compress = lua::toboolean(L, 3); } std::vector chunk_data; if (compress) { - size_t rle_compressed_size; - size_t gzip_compressed_size; + // world.get_chunk_data is only available in the main Lua state + static util::Buffer rlebuffer; + if (rlebuffer.size() < CHUNK_DATA_LEN * 2) { + rlebuffer = util::Buffer(CHUNK_DATA_LEN * 2); + } + 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 + + size_t rle_compressed_size = + extrle::encode16(data, CHUNK_DATA_LEN, rlebuffer.data()); + + const auto gzip_compressed_data = gzip::compress( + rlebuffer.data(), rle_compressed_size ); auto tmp = dataio::h2le(rle_compressed_size); - chunk_data.reserve(gzip_compressed_size + sizeof(tmp)); + chunk_data.reserve(gzip_compressed_data.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 + gzip_compressed_data.data(), + gzip_compressed_data.data() + gzip_compressed_data.size() ); } else { const auto& data = chunk->encode(); @@ -174,10 +174,10 @@ static int l_get_chunk_data(lua::State* L) { } static int l_set_chunk_data(lua::State* L) { - int x = (int)lua::tointeger(L, 1); - int y = (int)lua::tointeger(L, 2); + int x = static_cast(lua::tointeger(L, 1)); + int y = static_cast(lua::tointeger(L, 2)); auto buffer = lua::touserdata(L, 3); - bool is_compressed = false; + bool is_compressed = true; if (lua::gettop(L) >= 4) { is_compressed = lua::toboolean(L, 4); } @@ -207,38 +207,32 @@ static int l_set_chunk_data(lua::State* L) { } auto chunksController = controller->getChunksController(); - if (chunksController == nullptr) { - return 1; + if (chunksController->lighting == nullptr) { + return lua::pushboolean(L, true); } Lighting& lighting = *chunksController->lighting; chunk->updateHeights(); - lighting.buildSkyLight(x, y); - chunk->flags.modified = true; + chunk->flags.loadedLights = false; + chunk->flags.lighted = false; + chunk->setModifiedAndUnsaved(); + Lighting::prebuildSkyLight(*chunk, *indices); lighting.onChunkLoaded(x, y, true); - chunk = level->chunks->getChunk(x - 1, y); - if (chunk != nullptr) { - chunk->flags.modified = true; - lighting.onChunkLoaded(x - 1, y, true); - } - chunk = level->chunks->getChunk(x + 1, y); - if (chunk != nullptr) { - chunk->flags.modified = true; - lighting.onChunkLoaded(x + 1, y, true); - } - chunk = level->chunks->getChunk(x, y - 1); - if (chunk != nullptr) { - chunk->flags.modified = true; - lighting.onChunkLoaded(x, y - 1, true); - } - chunk = level->chunks->getChunk(x, y + 1); - if (chunk != nullptr) { - chunk->flags.modified = true; - lighting.onChunkLoaded(x, y + 1, true); + for (int lz = -1; lz <= 1; lz++) { + for (int lx = -1; lx <= 1; lx++) { + if (std::abs(lx) + std::abs(lz) != 1) { + continue; + } + chunk = level->chunks->getChunk(x + lx, y + lz); + if (chunk != nullptr) { + chunk->setModifiedAndUnsaved(); + lighting.onChunkLoaded(x - 1, y, true); + } + } } - return 1; + return lua::pushboolean(L, true); } static int l_count_chunks(lua::State* L) { From 29e018cff8183872ab6400b745b338bf967d27b2 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Jan 2025 20:11:29 +0300 Subject: [PATCH 04/21] fix chunk mesh refreshing --- src/graphics/render/ChunksRenderer.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index da40d822..6e6b4bd3 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -135,7 +135,7 @@ const Mesh* ChunksRenderer::getOrRender( if (found == meshes.end()) { return render(chunk, important); } - if (chunk->flags.modified) { + if (chunk->flags.modified && chunk->flags.lighted) { render(chunk, important); } return found->second.mesh.get(); @@ -149,9 +149,17 @@ const Mesh* ChunksRenderer::retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ) { auto chunk = chunks.getChunks()[index]; - if (chunk == nullptr || !chunk->flags.lighted) { + if (chunk == nullptr) { return nullptr; } + if (!chunk->flags.lighted) { + const auto& found = meshes.find({chunk->x, chunk->z}); + if (found == meshes.end()) { + return nullptr; + } else { + return found->second.mesh.get(); + } + } float distance = glm::distance( camera.position, glm::vec3( From d7ad7ff460db44118b001c494b93347e0b8ff313 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Jan 2025 22:58:41 +0300 Subject: [PATCH 05/21] add Chat hotkey --- res/config/bindings.toml | 1 + res/scripts/stdlib.lua | 8 ++++++++ res/texts/en_US.txt | 1 + res/texts/ru_RU.txt | 1 + 4 files changed, 11 insertions(+) diff --git a/res/config/bindings.toml b/res/config/bindings.toml index 426a580f..27f02342 100644 --- a/res/config/bindings.toml +++ b/res/config/bindings.toml @@ -19,3 +19,4 @@ player.pick="mouse:middle" player.drop="key:q" player.fast_interaction="key:x" hud.inventory="key:tab" +hud.chat="key:t" diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index ad36a221..c9f38835 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -377,6 +377,14 @@ function __vc_on_hud_open() hud.show_overlay("core:console", false, {"console"}) end) end) + input.add_callback("hud.chat", function() + if hud.is_paused() then + return + end + time.post_runnable(function() + hud.show_overlay("core:console", false, {"chat"}) + end) + end) end local RULES_FILE = "world:rules.toml" diff --git a/res/texts/en_US.txt b/res/texts/en_US.txt index e9b23897..732e2d66 100644 --- a/res/texts/en_US.txt +++ b/res/texts/en_US.txt @@ -33,6 +33,7 @@ movement.sprint=Sprint movement.crouch=Crouch movement.cheat=Cheat hud.inventory=Inventory +hud.chat=Chat player.pick=Pick Block player.attack=Attack player.destroy=Destroy diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt index d3c40893..80a7ba6a 100644 --- a/res/texts/ru_RU.txt +++ b/res/texts/ru_RU.txt @@ -103,6 +103,7 @@ movement.sprint=Ускорение movement.crouch=Красться movement.cheat=Чит hud.inventory=Инвентарь +hud.chat=Чат player.pick=Подобрать Блок player.attack=Атаковать player.destroy=Сломать From fe210708e5502a3525a99317064b83d78b049a73 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Jan 2025 23:03:19 +0300 Subject: [PATCH 06/21] fix --- src/logic/scripting/lua/libs/libworld.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 832f2e2e..073e7f05 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -206,16 +206,18 @@ static int l_set_chunk_data(lua::State* L) { chunk->decode(buffer->data().data()); } + chunk->setModifiedAndUnsaved(); + chunk->updateHeights(); + auto chunksController = controller->getChunksController(); if (chunksController->lighting == nullptr) { return lua::pushboolean(L, true); } Lighting& lighting = *chunksController->lighting; - chunk->updateHeights(); chunk->flags.loadedLights = false; chunk->flags.lighted = false; - chunk->setModifiedAndUnsaved(); + Lighting::prebuildSkyLight(*chunk, *indices); lighting.onChunkLoaded(x, y, true); @@ -226,7 +228,7 @@ static int l_set_chunk_data(lua::State* L) { } chunk = level->chunks->getChunk(x + lx, y + lz); if (chunk != nullptr) { - chunk->setModifiedAndUnsaved(); + chunk->flags.modified = true; lighting.onChunkLoaded(x - 1, y, true); } } From 077de25acc2cc51ecc17ff6a667256a180ac1402 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 11 Jan 2025 23:38:43 +0300 Subject: [PATCH 07/21] refactor --- src/logic/scripting/lua/libs/libworld.cpp | 98 +++++++++++------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 073e7f05..60183ab3 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -123,6 +123,41 @@ static int l_get_generator(lua::State* L) { return lua::pushstring(L, require_world_info().generator); } +static std::vector prepare_chunk_data(const Chunk& chunk, bool compress) { + auto data = chunk.encode(); + + std::vector chunkData; + if (compress) { + // world.get_chunk_data is only available in the main Lua state + static util::Buffer rleBuffer; + if (rleBuffer.size() < CHUNK_DATA_LEN * 2) { + rleBuffer = util::Buffer(CHUNK_DATA_LEN * 2); + } + size_t rleCompressedSize = + extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); + + const auto gzipCompressedData = gzip::compress( + rleBuffer.data(), rleCompressedSize + ); + auto tmp = dataio::h2le(rleCompressedSize); + chunkData.reserve(gzipCompressedData.size() + sizeof(tmp)); + chunkData.insert( + chunkData.begin() + 0, (char*)&tmp, ((char*)&tmp) + sizeof(tmp) + ); + chunkData.insert( + chunkData.begin() + sizeof(tmp), + gzipCompressedData.data(), + gzipCompressedData.data() + gzipCompressedData.size() + ); + } else { + chunkData.reserve(CHUNK_DATA_LEN); + chunkData.insert( + chunkData.begin(), data.get(), data.get() + CHUNK_DATA_LEN + ); + } + return chunkData; +} + static int l_get_chunk_data(lua::State* L) { int x = static_cast(lua::tointeger(L, 1)); int y = static_cast(lua::tointeger(L, 2)); @@ -131,73 +166,38 @@ static int l_get_chunk_data(lua::State* L) { lua::pushnil(L); return 0; } - bool compress = true; if (lua::gettop(L) >= 3) { compress = lua::toboolean(L, 3); } - std::vector chunk_data; - if (compress) { - // world.get_chunk_data is only available in the main Lua state - static util::Buffer rlebuffer; - if (rlebuffer.size() < CHUNK_DATA_LEN * 2) { - rlebuffer = util::Buffer(CHUNK_DATA_LEN * 2); - } - - const auto& data_ptr = chunk->encode(); - ubyte* data = data_ptr.get(); - - size_t rle_compressed_size = - extrle::encode16(data, CHUNK_DATA_LEN, rlebuffer.data()); - - const auto gzip_compressed_data = gzip::compress( - rlebuffer.data(), rle_compressed_size - ); - auto tmp = dataio::h2le(rle_compressed_size); - chunk_data.reserve(gzip_compressed_data.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.data(), - gzip_compressed_data.data() + gzip_compressed_data.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 - ); - } - return lua::newuserdata(L, chunk_data); + auto chunkData = prepare_chunk_data(*chunk, compress); + return lua::newuserdata(L, std::move(chunkData)); } static int l_set_chunk_data(lua::State* L) { int x = static_cast(lua::tointeger(L, 1)); int y = static_cast(lua::tointeger(L, 2)); auto buffer = lua::touserdata(L, 3); - bool is_compressed = true; + bool isCompressed = true; if (lua::gettop(L) >= 4) { - is_compressed = lua::toboolean(L, 4); + isCompressed = 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 = - 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, + if (isCompressed) { + std::vector& rawData = buffer->data(); + size_t gzipDecompressedSize = dataio::le2h(*(size_t*)(rawData.data())); + auto rleData = compression::decompress( + rawData.data() + sizeof(gzipDecompressedSize), + buffer->data().size() - sizeof(gzipDecompressedSize), + gzipDecompressedSize, compression::Method::GZIP ); - const auto& data = compression::decompress( - rle_data.get(), - gzip_decompressed_size, + auto data = compression::decompress( + rleData.get(), + gzipDecompressedSize, CHUNK_DATA_LEN, compression::Method::EXTRLE16 ); From c5fa6935a6bea4b4d823d860fafadf31c45e0f9b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 01:47:07 +0300 Subject: [PATCH 08/21] add metadata to chunk data used in world.get/set_chunk_data --- src/logic/scripting/lua/libs/libworld.cpp | 100 +++++++++------------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 60183ab3..ddba261e 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -7,6 +7,7 @@ #include "coders/compression.hpp" #include "coders/gzip.hpp" #include "coders/json.hpp" +#include "coders/byte_utils.hpp" #include "coders/rle.hpp" #include "engine/Engine.hpp" #include "files/engine_paths.hpp" @@ -123,39 +124,29 @@ static int l_get_generator(lua::State* L) { return lua::pushstring(L, require_world_info().generator); } -static std::vector prepare_chunk_data(const Chunk& chunk, bool compress) { +static std::vector prepare_chunk_data(const Chunk& chunk) { auto data = chunk.encode(); - std::vector chunkData; - if (compress) { - // world.get_chunk_data is only available in the main Lua state - static util::Buffer rleBuffer; - if (rleBuffer.size() < CHUNK_DATA_LEN * 2) { - rleBuffer = util::Buffer(CHUNK_DATA_LEN * 2); - } - size_t rleCompressedSize = - extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); - - const auto gzipCompressedData = gzip::compress( - rleBuffer.data(), rleCompressedSize - ); - auto tmp = dataio::h2le(rleCompressedSize); - chunkData.reserve(gzipCompressedData.size() + sizeof(tmp)); - chunkData.insert( - chunkData.begin() + 0, (char*)&tmp, ((char*)&tmp) + sizeof(tmp) - ); - chunkData.insert( - chunkData.begin() + sizeof(tmp), - gzipCompressedData.data(), - gzipCompressedData.data() + gzipCompressedData.size() - ); - } else { - chunkData.reserve(CHUNK_DATA_LEN); - chunkData.insert( - chunkData.begin(), data.get(), data.get() + CHUNK_DATA_LEN - ); + /// world.get_chunk_data is only available in the main Lua state + static util::Buffer rleBuffer; + if (rleBuffer.size() < CHUNK_DATA_LEN * 2) { + rleBuffer = util::Buffer(CHUNK_DATA_LEN * 2); } - return chunkData; + size_t rleCompressedSize = + extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); + + const auto gzipCompressedData = gzip::compress( + rleBuffer.data(), rleCompressedSize + ); + auto metadataBytes = chunk.blocksMetadata.serialize(); + + ByteBuilder builder(2 + 8 + gzipCompressedData.size() + metadataBytes.size()); + builder.putInt16(0); // header + builder.putInt32(gzipCompressedData.size()); + builder.put(gzipCompressedData.data(), gzipCompressedData.size()); + builder.putInt32(metadataBytes.size()); + builder.put(metadataBytes.data(), metadataBytes.size()); + return builder.build(); } static int l_get_chunk_data(lua::State* L) { @@ -166,11 +157,7 @@ static int l_get_chunk_data(lua::State* L) { lua::pushnil(L); return 0; } - bool compress = true; - if (lua::gettop(L) >= 3) { - compress = lua::toboolean(L, 3); - } - auto chunkData = prepare_chunk_data(*chunk, compress); + auto chunkData = prepare_chunk_data(*chunk); return lua::newuserdata(L, std::move(chunkData)); } @@ -178,33 +165,29 @@ static int l_set_chunk_data(lua::State* L) { int x = static_cast(lua::tointeger(L, 1)); int y = static_cast(lua::tointeger(L, 2)); auto buffer = lua::touserdata(L, 3); - bool isCompressed = true; - if (lua::gettop(L) >= 4) { - isCompressed = lua::toboolean(L, 4); - } auto chunk = level->chunks->getChunk(x, y); if (chunk == nullptr) { return 0; } - if (isCompressed) { - std::vector& rawData = buffer->data(); - size_t gzipDecompressedSize = dataio::le2h(*(size_t*)(rawData.data())); - auto rleData = compression::decompress( - rawData.data() + sizeof(gzipDecompressedSize), - buffer->data().size() - sizeof(gzipDecompressedSize), - gzipDecompressedSize, - compression::Method::GZIP - ); - auto data = compression::decompress( - rleData.get(), - gzipDecompressedSize, - CHUNK_DATA_LEN, - compression::Method::EXTRLE16 - ); - chunk->decode(data.get()); - } else { - chunk->decode(buffer->data().data()); - } + + std::vector& rawData = buffer->data(); + + ByteReader reader(rawData.data(), rawData.size()); + + uint16_t header = reader.getInt16(); + size_t gzipCompressedSize = reader.getInt32(); + + auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize); + reader.skip(gzipCompressedSize); + + /// world.get_chunk_data is only available in the main Lua state + static util::Buffer voxelData (CHUNK_DATA_LEN); + extrle::decode16(rleData.data(), rleData.size(), voxelData.data()); + chunk->decode(voxelData.data()); + + size_t metadataSize = reader.getInt32(); + chunk->blocksMetadata.deserialize(reader.pointer(), metadataSize); + reader.skip(metadataSize); chunk->setModifiedAndUnsaved(); chunk->updateHeights(); @@ -233,7 +216,6 @@ static int l_set_chunk_data(lua::State* L) { } } } - return lua::pushboolean(L, true); } From 41f6194fc1354ef2b2c487b9c21946e5bb9c6bb3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 03:05:58 +0300 Subject: [PATCH 09/21] introduce compressed_chunks namespace --- src/logic/scripting/lua/libs/libworld.cpp | 106 +++++++--------------- src/voxels/compressed_chunks.cpp | 61 +++++++++++++ src/voxels/compressed_chunks.hpp | 12 +++ 3 files changed, 104 insertions(+), 75 deletions(-) create mode 100644 src/voxels/compressed_chunks.cpp create mode 100644 src/voxels/compressed_chunks.hpp diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index ddba261e..5d936842 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -4,11 +4,7 @@ #include "api_lua.hpp" #include "assets/AssetsLoader.hpp" -#include "coders/compression.hpp" -#include "coders/gzip.hpp" #include "coders/json.hpp" -#include "coders/byte_utils.hpp" -#include "coders/rle.hpp" #include "engine/Engine.hpp" #include "files/engine_paths.hpp" #include "files/files.hpp" @@ -16,6 +12,7 @@ #include "voxels/Chunk.hpp" #include "voxels/Chunks.hpp" #include "voxels/GlobalChunks.hpp" +#include "voxels/compressed_chunks.hpp" #include "world/Level.hpp" #include "world/World.hpp" #include "logic/LevelController.hpp" @@ -124,98 +121,57 @@ static int l_get_generator(lua::State* L) { return lua::pushstring(L, require_world_info().generator); } -static std::vector prepare_chunk_data(const Chunk& chunk) { - auto data = chunk.encode(); - - /// world.get_chunk_data is only available in the main Lua state - static util::Buffer rleBuffer; - if (rleBuffer.size() < CHUNK_DATA_LEN * 2) { - rleBuffer = util::Buffer(CHUNK_DATA_LEN * 2); - } - size_t rleCompressedSize = - extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); - - const auto gzipCompressedData = gzip::compress( - rleBuffer.data(), rleCompressedSize - ); - auto metadataBytes = chunk.blocksMetadata.serialize(); - - ByteBuilder builder(2 + 8 + gzipCompressedData.size() + metadataBytes.size()); - builder.putInt16(0); // header - builder.putInt32(gzipCompressedData.size()); - builder.put(gzipCompressedData.data(), gzipCompressedData.size()); - builder.putInt32(metadataBytes.size()); - builder.put(metadataBytes.data(), metadataBytes.size()); - return builder.build(); -} - static int l_get_chunk_data(lua::State* L) { int x = static_cast(lua::tointeger(L, 1)); - int y = static_cast(lua::tointeger(L, 2)); - const auto& chunk = level->chunks->getChunk(x, y); + int z = static_cast(lua::tointeger(L, 2)); + const auto& chunk = level->chunks->getChunk(x, z); if (chunk == nullptr) { lua::pushnil(L); return 0; } - auto chunkData = prepare_chunk_data(*chunk); + auto chunkData = compressed_chunks::encode(*chunk); return lua::newuserdata(L, std::move(chunkData)); } -static int l_set_chunk_data(lua::State* L) { - int x = static_cast(lua::tointeger(L, 1)); - int y = static_cast(lua::tointeger(L, 2)); - auto buffer = lua::touserdata(L, 3); - auto chunk = level->chunks->getChunk(x, y); - if (chunk == nullptr) { - return 0; - } - - std::vector& rawData = buffer->data(); - - ByteReader reader(rawData.data(), rawData.size()); - - uint16_t header = reader.getInt16(); - size_t gzipCompressedSize = reader.getInt32(); - - auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize); - reader.skip(gzipCompressedSize); - - /// world.get_chunk_data is only available in the main Lua state - static util::Buffer voxelData (CHUNK_DATA_LEN); - extrle::decode16(rleData.data(), rleData.size(), voxelData.data()); - chunk->decode(voxelData.data()); - - size_t metadataSize = reader.getInt32(); - chunk->blocksMetadata.deserialize(reader.pointer(), metadataSize); - reader.skip(metadataSize); - - chunk->setModifiedAndUnsaved(); - chunk->updateHeights(); - +static void integrate_chunk_client(Chunk& chunk) { + int x = chunk.x; + int z = chunk.z; auto chunksController = controller->getChunksController(); - if (chunksController->lighting == nullptr) { - return lua::pushboolean(L, true); - } - Lighting& lighting = *chunksController->lighting; - chunk->flags.loadedLights = false; - chunk->flags.lighted = false; + chunk.flags.loadedLights = false; + chunk.flags.lighted = false; - Lighting::prebuildSkyLight(*chunk, *indices); - lighting.onChunkLoaded(x, y, true); + Lighting::prebuildSkyLight(chunk, *indices); + lighting.onChunkLoaded(x, z, true); for (int lz = -1; lz <= 1; lz++) { for (int lx = -1; lx <= 1; lx++) { if (std::abs(lx) + std::abs(lz) != 1) { continue; } - chunk = level->chunks->getChunk(x + lx, y + lz); - if (chunk != nullptr) { - chunk->flags.modified = true; - lighting.onChunkLoaded(x - 1, y, true); + if (auto other = level->chunks->getChunk(x + lx, z + lz)) { + other->flags.modified = true; + lighting.onChunkLoaded(x - 1, z, true); } } } +} + +static int l_set_chunk_data(lua::State* L) { + int x = static_cast(lua::tointeger(L, 1)); + int z = static_cast(lua::tointeger(L, 2)); + auto buffer = lua::touserdata(L, 3); + auto chunk = level->chunks->getChunk(x, z); + if (chunk == nullptr) { + return 0; + } + compressed_chunks::decode( + *chunk, buffer->data().data(), buffer->data().size() + ); + if (controller->getChunksController()->lighting == nullptr) { + return lua::pushboolean(L, true); + } + integrate_chunk_client(*chunk); return lua::pushboolean(L, true); } diff --git a/src/voxels/compressed_chunks.cpp b/src/voxels/compressed_chunks.cpp new file mode 100644 index 00000000..0e6772af --- /dev/null +++ b/src/voxels/compressed_chunks.cpp @@ -0,0 +1,61 @@ +#include "compressed_chunks.hpp" + +#include "coders/rle.hpp" +#include "coders/gzip.hpp" +#include "coders/byte_utils.hpp" +#include "voxels/Chunk.hpp" + +inline constexpr int HAS_VOXELS = 0x1; +inline constexpr int HAS_METADATA = 0x2; + +std::vector compressed_chunks::encode(const Chunk& chunk) { + auto data = chunk.encode(); + + /// world.get_chunk_data is only available in the main Lua state + static util::Buffer rleBuffer; + if (rleBuffer.size() < CHUNK_DATA_LEN * 2) { + rleBuffer = util::Buffer(CHUNK_DATA_LEN * 2); + } + size_t rleCompressedSize = + extrle::encode16(data.get(), CHUNK_DATA_LEN, rleBuffer.data()); + + const auto gzipCompressedData = gzip::compress( + rleBuffer.data(), rleCompressedSize + ); + auto metadataBytes = chunk.blocksMetadata.serialize(); + + ByteBuilder builder(2 + 8 + gzipCompressedData.size() + metadataBytes.size()); + builder.put(HAS_VOXELS | HAS_METADATA); // flags + builder.put(0); // reserved + builder.putInt32(gzipCompressedData.size()); + builder.put(gzipCompressedData.data(), gzipCompressedData.size()); + builder.putInt32(metadataBytes.size()); + builder.put(metadataBytes.data(), metadataBytes.size()); + return builder.build(); +} + +void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) { + ByteReader reader(src, size); + + ubyte flags = reader.get(); + reader.skip(1); // reserved byte + + if (flags & HAS_VOXELS) { + size_t gzipCompressedSize = reader.getInt32(); + + auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize); + reader.skip(gzipCompressedSize); + + /// world.get_chunk_data is only available in the main Lua state + static util::Buffer voxelData (CHUNK_DATA_LEN); + extrle::decode16(rleData.data(), rleData.size(), voxelData.data()); + chunk.decode(voxelData.data()); + chunk.updateHeights(); + } + if (flags & HAS_METADATA) { + size_t metadataSize = reader.getInt32(); + chunk.blocksMetadata.deserialize(reader.pointer(), metadataSize); + reader.skip(metadataSize); + } + chunk.setModifiedAndUnsaved(); +} diff --git a/src/voxels/compressed_chunks.hpp b/src/voxels/compressed_chunks.hpp new file mode 100644 index 00000000..dc0bc5b6 --- /dev/null +++ b/src/voxels/compressed_chunks.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "typedefs.hpp" + +#include + +class Chunk; + +namespace compressed_chunks { + std::vector encode(const Chunk& chunk); + void decode(Chunk& chunk, const ubyte* src, size_t size); +} From fc9c096873a6f69b1eb91b27abb1d57a77d8d7da Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 03:34:50 +0300 Subject: [PATCH 10/21] cleanup --- src/voxels/Chunk.cpp | 13 ------------- src/voxels/Chunk.hpp | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index a32fc8ba..2c1f4fd8 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -13,19 +13,6 @@ Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos) { top = CHUNK_H; } -bool Chunk::isEmpty() const { - int id = -1; - for (uint i = 0; i < CHUNK_VOL; i++) { - if (voxels[i].id != id) { - if (id != -1) - return false; - else - id = voxels[i].id; - } - } - return true; -} - void Chunk::updateHeights() { for (uint i = 0; i < CHUNK_VOL; i++) { if (voxels[i].id != 0) { diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 55cdac21..3ce6e641 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -11,6 +11,7 @@ #include "maths/aabb.hpp" #include "voxel.hpp" +/// @brief Total bytes number of chunk voxel data inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL * 4; class ContentReport; @@ -45,8 +46,7 @@ public: Chunk(int x, int z); - bool isEmpty() const; - + /// @brief Refresh `bottom` and `top` values void updateHeights(); // unused From cafaa3a168ba162859f12f93a38a29c4168e6abb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 03:43:35 +0300 Subject: [PATCH 11/21] update doc/*/scripting/builtins/libworld.md --- doc/en/scripting/builtins/libworld.md | 14 ++++++++++++++ doc/ru/scripting/builtins/libworld.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/doc/en/scripting/builtins/libworld.md b/doc/en/scripting/builtins/libworld.md index fc18773e..97c6fdee 100644 --- a/doc/en/scripting/builtins/libworld.md +++ b/doc/en/scripting/builtins/libworld.md @@ -47,4 +47,18 @@ world.is_night() -> bool -- Returns the total number of chunks loaded into memory world.count_chunks() -> int + +-- Returns the compressed chunk data to send. +-- Currently includes: +-- 1. Voxel data (id and state) +-- 2. Voxel metadata (fields) +world.get_chunk_data(x: int, z: int) -> Bytearray + +-- Modifies the chunk based on the compressed data. +-- Returns true if the chunk exists. +world.set_chunk_data( + x: int, z: int, + -- compressed chunk data + data: Bytearray +) -> bool ``` diff --git a/doc/ru/scripting/builtins/libworld.md b/doc/ru/scripting/builtins/libworld.md index 0467d784..a7e0e5a6 100644 --- a/doc/ru/scripting/builtins/libworld.md +++ b/doc/ru/scripting/builtins/libworld.md @@ -46,4 +46,18 @@ world.is_night() -> bool -- Возвращает общее количество загруженных в память чанков world.count_chunks() -> int + +-- Возвращает сжатые данные чанка для отправки. +-- На данный момент включает: +-- 1. Данные вокселей (id и состояние) +-- 2. Метаданные (поля) вокселей +world.get_chunk_data(x: int, z: int) -> Bytearray + +-- Изменяет чанк на основе сжатых данных. +-- Возвращает true если чанк существует. +world.set_chunk_data( + x: int, z: int, + -- сжатые данные чанка + data: Bytearray +) -> bool ``` From 22c7cb8398ddf97d70ae4df1b75406b2996145f9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 05:41:42 +0300 Subject: [PATCH 12/21] add `on_chunk_present` and `on_chunk_remove` events --- src/content/ContentPack.hpp | 2 ++ src/graphics/render/WorldRenderer.cpp | 2 +- src/logic/LevelController.cpp | 9 +++++++ src/logic/scripting/scripting.cpp | 34 +++++++++++++++++++++++++++ src/logic/scripting/scripting.hpp | 5 ++++ src/voxels/Chunks.cpp | 4 ++-- src/voxels/GlobalChunks.cpp | 3 +++ src/world/Level.cpp | 7 +++--- src/world/LevelEvents.hpp | 8 ++++--- 9 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index c8e0de9b..84e835dd 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -109,6 +109,8 @@ struct WorldFuncsSet { bool onblockbroken; bool onblockinteract; bool onplayertick; + bool onchunkpresent; + bool onchunkremove; }; class ContentPackRuntime { diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index f83363cd..cefb61d5 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -89,7 +89,7 @@ WorldRenderer::WorldRenderer( ) { auto& settings = engine.getSettings(); level.events->listen( - EVT_CHUNK_HIDDEN, + LevelEventType::CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) { chunks->unload(chunk); } ); auto assets = engine.getAssets(); diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 15ed2eb8..06fd6e96 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -14,6 +14,7 @@ #include "scripting/scripting.hpp" #include "lighting/Lighting.hpp" #include "settings.hpp" +#include "world/LevelEvents.hpp" #include "world/Level.hpp" #include "world/World.hpp" @@ -26,6 +27,14 @@ LevelController::LevelController( level(std::move(levelPtr)), chunks(std::make_unique(*level)), playerTickClock(20, 3) { + + level->events->listen(LevelEventType::CHUNK_PRESENT, [](auto, Chunk* chunk) { + scripting::on_chunk_present(*chunk, chunk->flags.loaded); + }); + level->events->listen(LevelEventType::CHUNK_UNLOAD, [](auto, Chunk* chunk) { + scripting::on_chunk_remove(*chunk); + }); + if (clientPlayer) { chunks->lighting = std::make_unique( level->content, *clientPlayer->chunks diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index b8f00d3f..e19a82bc 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -24,6 +24,7 @@ #include "util/stringutil.hpp" #include "util/timeutil.hpp" #include "voxels/Block.hpp" +#include "voxels/Chunk.hpp" #include "world/Level.hpp" #include "interfaces/Process.hpp" @@ -411,6 +412,35 @@ bool scripting::on_block_interact( ); } +void scripting::on_chunk_present(const Chunk& chunk, bool loaded) { + auto args = [&chunk, loaded](lua::State* L) { + lua::pushvec_stack<2>(L, {chunk.x, chunk.z}); + lua::pushboolean(L, loaded); + return 3; + }; + for (auto& [packid, pack] : content->getPacks()) { + if (pack->worldfuncsset.onchunkpresent) { + lua::emit_event( + lua::get_main_state(), packid + ":.chunkpresent", args + ); + } + } +} + +void scripting::on_chunk_remove(const Chunk& chunk) { + auto args = [&chunk](lua::State* L) { + lua::pushvec_stack<2>(L, {chunk.x, chunk.z}); + return 2; + }; + for (auto& [packid, pack] : content->getPacks()) { + if (pack->worldfuncsset.onchunkremove) { + lua::emit_event( + lua::get_main_state(), packid + ":.chunkremove", args + ); + } + } +} + void scripting::on_player_tick(Player* player, int tps) { auto args = [=](lua::State* L) { lua::pushinteger(L, player ? player->getId() : -1); @@ -837,6 +867,10 @@ void scripting::load_world_script( register_event(env, "on_block_interact", prefix + ":.blockinteract"); funcsset.onplayertick = register_event(env, "on_player_tick", prefix + ":.playertick"); + funcsset.onchunkpresent = + register_event(env, "on_chunk_present", prefix + ":.chunkpresent"); + funcsset.onchunkremove = + register_event(env, "on_chunk_remove", prefix + ":.chunkremove"); } void scripting::load_layout_script( diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index fb552f66..ee4be4f8 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -17,6 +17,7 @@ struct ContentPack; class ContentIndices; class Level; class Block; +class Chunk; class Player; struct ItemDef; class Inventory; @@ -84,6 +85,10 @@ namespace scripting { Player* player, const Block& block, const glm::ivec3& pos ); bool on_block_interact(Player* player, const Block& block, const glm::ivec3& pos); + + void on_chunk_present(const Chunk& chunk, bool loaded); + void on_chunk_remove(const Chunk& chunk); + void on_player_tick(Player* player, int tps); /// @brief Called on RMB click with the item selected diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index f65c1863..bf9b2990 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -34,7 +34,7 @@ Chunks::Chunks( areaMap(w, d) { areaMap.setCenter(ox-w/2, oz-d/2); areaMap.setOutCallback([this](int, int, const auto& chunk) { - this->events->trigger(EVT_CHUNK_HIDDEN, chunk.get()); + this->events->trigger(LevelEventType::CHUNK_HIDDEN, chunk.get()); }); } @@ -323,7 +323,7 @@ void Chunks::resize(uint32_t newW, uint32_t newD) { bool Chunks::putChunk(const std::shared_ptr& chunk) { if (areaMap.set(chunk->x, chunk->z, chunk)) { if (events) { - events->trigger(LevelEventType::EVT_CHUNK_SHOWN, chunk.get()); + events->trigger(LevelEventType::CHUNK_SHOWN, chunk.get()); } return true; } diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 8f8e05bb..1e67a374 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -12,6 +12,7 @@ #include "objects/Entities.hpp" #include "voxels/blocks_agent.hpp" #include "typedefs.hpp" +#include "world/LevelEvents.hpp" #include "world/Level.hpp" #include "world/World.hpp" #include "Block.hpp" @@ -125,6 +126,8 @@ std::shared_ptr GlobalChunks::create(int x, int z) { chunk->flags.loadedLights = true; } chunk->blocksMetadata = regions.getBlocksData(chunk->x, chunk->z); + + level.events->trigger(LevelEventType::CHUNK_PRESENT, chunk.get()); return chunk; } diff --git a/src/world/Level.cpp b/src/world/Level.cpp index 7ea871ee..460b34a4 100644 --- a/src/world/Level.cpp +++ b/src/world/Level.cpp @@ -52,13 +52,14 @@ Level::Level( entities->setNextID(worldInfo.nextEntityId); } - events->listen(LevelEventType::EVT_CHUNK_SHOWN, [this](LevelEventType, Chunk* chunk) { + events->listen(LevelEventType::CHUNK_SHOWN, [this](LevelEventType, Chunk* chunk) { chunks->incref(chunk); }); - events->listen(LevelEventType::EVT_CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) { + events->listen(LevelEventType::CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) { chunks->decref(chunk); }); - chunks->setOnUnload([this](const Chunk& chunk) { + chunks->setOnUnload([this](Chunk& chunk) { + events->trigger(LevelEventType::CHUNK_UNLOAD, &chunk); AABB aabb = chunk.getAABB(); entities->despawn(entities->getAllInside(aabb)); }); diff --git a/src/world/LevelEvents.hpp b/src/world/LevelEvents.hpp index f7bbaa7f..8096428b 100644 --- a/src/world/LevelEvents.hpp +++ b/src/world/LevelEvents.hpp @@ -6,9 +6,11 @@ class Chunk; -enum LevelEventType { - EVT_CHUNK_SHOWN, - EVT_CHUNK_HIDDEN, +enum class LevelEventType { + CHUNK_SHOWN, + CHUNK_HIDDEN, + CHUNK_PRESENT, + CHUNK_UNLOAD, }; using ChunkEventFunc = std::function; From 89cde3e05e7cc9cfa96a79d66232da62ec1b4094 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 15:43:13 +0300 Subject: [PATCH 13/21] add missing includes --- src/util/HandlersList.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/HandlersList.hpp b/src/util/HandlersList.hpp index 5af5250d..737fdf36 100644 --- a/src/util/HandlersList.hpp +++ b/src/util/HandlersList.hpp @@ -1,7 +1,9 @@ #pragma once #include -#include +#include +#include +#include #include "typedefs.hpp" #include "delegates.hpp" From 80128a419075df35e7558aee11ddd43e0e0d53ba Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 17:14:01 +0300 Subject: [PATCH 14/21] add `on_inventory_open` and `on_inventory_closed` events --- src/content/ContentPack.hpp | 2 ++ src/frontend/hud.cpp | 9 +++++--- src/logic/scripting/scripting.cpp | 34 +++++++++++++++++++++++++++++++ src/logic/scripting/scripting.hpp | 3 +++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index 84e835dd..e4360bdc 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -111,6 +111,8 @@ struct WorldFuncsSet { bool onplayertick; bool onchunkpresent; bool onchunkremove; + bool oninventoryopen; + bool oninventoryclosed; }; class ContentPackRuntime { diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 3bf7cab2..fa7b539d 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -447,6 +447,8 @@ void Hud::openInventory( blockPos = block; currentblockid = chunks.require(block.x, block.y, block.z).id; add(HudElement(hud_element_mode::inventory_bound, doc, blockUI, false)); + + scripting::on_inventory_open(&player, *blockinv); } void Hud::showExchangeSlot() { @@ -461,7 +463,6 @@ void Hud::showExchangeSlot() { exchangeSlot->setInteractive(false); exchangeSlot->setZIndex(1); gui.store(SlotView::EXCHANGE_SLOT_NAME, exchangeSlot); - } void Hud::showOverlay( @@ -517,13 +518,15 @@ void Hud::dropExchangeSlot() { } void Hud::closeInventory() { + if (blockUI) { + scripting::on_inventory_closed(&player, *blockUI->getInventory()); + blockUI = nullptr; + } dropExchangeSlot(); gui.remove(SlotView::EXCHANGE_SLOT_NAME); exchangeSlot = nullptr; exchangeSlotInv = nullptr; inventoryOpen = false; - inventoryView = nullptr; - blockUI = nullptr; secondUI = nullptr; for (auto& element : elements) { diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index e19a82bc..d58879d3 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -441,6 +441,36 @@ void scripting::on_chunk_remove(const Chunk& chunk) { } } +void scripting::on_inventory_open(const Player* player, const Inventory& inventory) { + auto args = [player, &inventory](lua::State* L) { + lua::pushinteger(L, inventory.getId()); + lua::pushinteger(L, player ? player->getId() : -1); + return 2; + }; + for (auto& [packid, pack] : content->getPacks()) { + if (pack->worldfuncsset.oninventoryopen) { + lua::emit_event( + lua::get_main_state(), packid + ":.inventoryopen", args + ); + } + } +} + +void scripting::on_inventory_closed(const Player* player, const Inventory& inventory) { + auto args = [player, &inventory](lua::State* L) { + lua::pushinteger(L, inventory.getId()); + lua::pushinteger(L, player ? player->getId() : -1); + return 2; + }; + for (auto& [packid, pack] : content->getPacks()) { + if (pack->worldfuncsset.oninventoryclosed) { + lua::emit_event( + lua::get_main_state(), packid + ":.inventoryclosed", args + ); + } + } +} + void scripting::on_player_tick(Player* player, int tps) { auto args = [=](lua::State* L) { lua::pushinteger(L, player ? player->getId() : -1); @@ -871,6 +901,10 @@ void scripting::load_world_script( register_event(env, "on_chunk_present", prefix + ":.chunkpresent"); funcsset.onchunkremove = register_event(env, "on_chunk_remove", prefix + ":.chunkremove"); + funcsset.oninventoryopen = + register_event(env, "on_inventory_open", prefix + ":.inventoryopen"); + funcsset.oninventoryclosed = + register_event(env, "on_inventory_closed", prefix + ":.inventoryclosed"); } void scripting::load_layout_script( diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index ee4be4f8..b447de28 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -89,6 +89,9 @@ namespace scripting { void on_chunk_present(const Chunk& chunk, bool loaded); void on_chunk_remove(const Chunk& chunk); + void on_inventory_open(const Player* player, const Inventory& inventory); + void on_inventory_closed(const Player* player, const Inventory& inventory); + void on_player_tick(Player* player, int tps); /// @brief Called on RMB click with the item selected From 90fc55923467c1935f90a2eb38531a365ba61431 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 17:36:42 +0300 Subject: [PATCH 15/21] add `hud.open` inventory events support --- src/frontend/hud.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index fa7b539d..29b5df05 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -413,6 +413,7 @@ std::shared_ptr Hud::openInventory( } secondInvView->bind(inv, &content); add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false)); + scripting::on_inventory_open(&player, *inv); return inv; } @@ -522,6 +523,9 @@ void Hud::closeInventory() { scripting::on_inventory_closed(&player, *blockUI->getInventory()); blockUI = nullptr; } + if (secondInvView) { + scripting::on_inventory_closed(&player, *secondInvView->getInventory()); + } dropExchangeSlot(); gui.remove(SlotView::EXCHANGE_SLOT_NAME); exchangeSlot = nullptr; From 918cb8aa329180f7fa650cfeb18e453f89994cb1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 19:43:06 +0300 Subject: [PATCH 16/21] update doc/*/scripting/events.md --- doc/en/scripting/events.md | 28 ++++++++++++++++++++++++++++ doc/ru/scripting/events.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/doc/en/scripting/events.md b/doc/en/scripting/events.md index cc820898..21e1cee5 100644 --- a/doc/en/scripting/events.md +++ b/doc/en/scripting/events.md @@ -126,6 +126,34 @@ function on_block_interact(blockid, x, y, z, playerid) -> bool Called on block RMB click interaction. Prevents block placing if **true** returned. +### Chunk Events (world.lua) + +```lua +function on_chunk_present(x: int, z: int, loaded: bool) +``` + +Called after a chunk is generated/loaded. If a previously saved chunk is loaded, `loaded` will be true. + +```lua +function on_chunk_remove(x: int, z: int) +``` + +Called when a chunk is unloaded from the world. + +### Inventory Events (world.lua) + +```lua +function on_inventory_open(invid: int, playerid: int) +``` + +Called when the inventory is opened. If the inventory was not opened directly by the player, playerid will be -1. + +```lua +function on_inventory_closed(invid: int, playerid: int) +``` + +Called when the inventory is closed. + ## Layout events Script *layouts/layout_name.xml.lua* events. diff --git a/doc/ru/scripting/events.md b/doc/ru/scripting/events.md index a5cc3e72..c7781879 100644 --- a/doc/ru/scripting/events.md +++ b/doc/ru/scripting/events.md @@ -126,6 +126,35 @@ function on_block_interact(blockid, x, y, z, playerid) -> bool Вызывается при нажатии на блок ПКМ. Предотвращает установку блоков, если возвращает `true` +### События чанков (world.lua) + +```lua +function on_chunk_present(x: int, z: int, loaded: bool) +``` + +Вызывается после генерации/загрузки чанка. В случае загрузки ранее сохраненного чанка `loaded` будет истинным. + +```lua +function on_chunk_remove(x: int, z: int) +``` + +Вызывается при выгрузке чанка из мира. + +### События инвентарей (world.lua) + +```lua +function on_inventory_open(invid: int, playerid: int) +``` + +Вызывается при открытии инвентаря. Если инвентарь был открыт не напрямую игроком, playerid будет равен -1. + +```lua +function on_inventory_closed(invid: int, playerid: int) +``` + +Вызывается при закрытии инвентаря. + + ## События макета События прописываются в файле `layouts/имя_макета.xml.lua`. From 5130907192390a557c131b56d5ee3db780039ff5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 12 Jan 2025 23:09:41 +0300 Subject: [PATCH 17/21] fix hud --- src/frontend/hud.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 29b5df05..01798503 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -531,6 +531,7 @@ void Hud::closeInventory() { exchangeSlot = nullptr; exchangeSlotInv = nullptr; inventoryOpen = false; + inventoryView = nullptr; secondUI = nullptr; for (auto& element : elements) { From 390d54c2122869ac1efd5167d65211a6e37c392a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 13 Jan 2025 02:52:59 +0300 Subject: [PATCH 18/21] fix segfault at attempt to create/open world when another is open --- src/engine/ServerMainloop.cpp | 2 +- src/logic/scripting/lua/libs/libcore.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index eb570e7b..b97919be 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -70,7 +70,7 @@ void ServerMainloop::run() { begin = system_clock::now(); } } - logger.info() << "test finished"; + logger.info() << "script finished"; } void ServerMainloop::setLevel(std::unique_ptr level) { diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 7946d301..3daebca5 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -55,6 +55,9 @@ static int l_new_world(lua::State* L) { auto name = lua::require_string(L, 1); auto seed = lua::require_string(L, 2); auto generator = lua::require_string(L, 3); + if (level != nullptr) { + throw std::runtime_error("world must be closed before"); + } auto controller = engine->getController(); controller->createWorld(name, seed, generator); return 0; @@ -64,7 +67,9 @@ static int l_new_world(lua::State* L) { /// @param name Name world static int l_open_world(lua::State* L) { auto name = lua::require_string(L, 1); - + if (level != nullptr) { + throw std::runtime_error("world must be closed before"); + } auto controller = engine->getController(); controller->openWorld(name, false); return 0; From b9707e11caea64ab534e1449e18fcd3d511d2a02 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 13 Jan 2025 04:20:48 +0300 Subject: [PATCH 19/21] fix lua::create_lambda and lua::create_lambda_nothrow --- src/logic/scripting/lua/lua_util.cpp | 4 ++-- src/logic/scripting/lua/lua_wrapper.hpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/logic/scripting/lua/lua_util.cpp b/src/logic/scripting/lua/lua_util.cpp index 8c3adaea..842c7859 100644 --- a/src/logic/scripting/lua/lua_util.cpp +++ b/src/logic/scripting/lua/lua_util.cpp @@ -268,9 +268,9 @@ KeyCallback lua::create_simple_handler(State* L) { scripting::common_func lua::create_lambda(State* L) { auto funcptr = create_lambda_handler(L); return [=](const std::vector& args) -> dv::value { - int top = gettop(L) + 1; if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) return nullptr; + int top = gettop(L) + 1; for (const auto& arg : args) { pushvalue(L, arg); } @@ -290,9 +290,9 @@ scripting::common_func lua::create_lambda(State* L) { scripting::common_func lua::create_lambda_nothrow(State* L) { auto funcptr = create_lambda_handler(L); return [=](const std::vector& args) -> dv::value { - int top = gettop(L) - 1; if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) return nullptr; + int top = gettop(L) - 1; for (const auto& arg : args) { pushvalue(L, arg); } diff --git a/src/logic/scripting/lua/lua_wrapper.hpp b/src/logic/scripting/lua/lua_wrapper.hpp index ee184cb1..8637babc 100644 --- a/src/logic/scripting/lua/lua_wrapper.hpp +++ b/src/logic/scripting/lua/lua_wrapper.hpp @@ -21,6 +21,11 @@ namespace lua { } inline void pop(lua::State* L, int n = 1) { +#ifndef NDEBUG + if (lua_gettop(L) < n) { + abort(); + } +#endif lua_pop(L, n); } inline void insert(lua::State* L, int idx) { From f772d527e2339c6c42a5f04c99ab11e32bc12cfe Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 13 Jan 2025 05:40:43 +0300 Subject: [PATCH 20/21] feat: nameless worlds --- src/logic/LevelController.cpp | 4 ++++ src/world/World.cpp | 7 ++++++- src/world/World.hpp | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 06fd6e96..47a6384d 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -108,6 +108,10 @@ void LevelController::update(float delta, bool pause) { void LevelController::saveWorld() { auto world = level->getWorld(); + if (world->isNameless()) { + logger.info() << "nameless world will not be saved"; + return; + } logger.info() << "writing world '" << world->getName() << "'"; world->wfile->createDirectories(); scripting::on_world_save(); diff --git a/src/world/World.cpp b/src/world/World.cpp index a3b83742..54785862 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -94,7 +94,12 @@ std::unique_ptr World::create( content, packs ); - logger.info() << "created world '" << name << "' (" << directory.u8string() << ")"; + if (name.empty()) { + logger.info() << "created nameless world"; + } else { + logger.info() << "created world '" << name << "' (" + << directory.u8string() << ")"; + } logger.info() << "world seed: " << seed << " generator: " << generator; return std::make_unique(std::move(world), content, settings); } diff --git a/src/world/World.hpp b/src/world/World.hpp index 552f70ec..da1ebd81 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -140,6 +140,10 @@ public: /// @brief Get world generator id std::string getGenerator() const; + bool isNameless() const { + return info.name.empty(); + } + WorldInfo& getInfo() { return info; } From d3e2ad5e99a18ebe39412cf35e9ca4e3150f252c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 13 Jan 2025 19:39:12 +0300 Subject: [PATCH 21/21] set appimage CMAKE_BUILD_TYPE to Release --- .github/workflows/appimage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 54046d33..cb599308 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -32,11 +32,11 @@ jobs: # install EnTT git clone https://github.com/skypjack/entt.git cd entt/build - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + cmake -DCMAKE_BUILD_TYPE=Release .. sudo make install cd ../.. - name: Configure - run: cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON + run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON - name: Build run: cmake --build build -t install - name: Run tests