diff --git a/CMakeLists.txt b/CMakeLists.txt index f465fcb3..a56457bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,4 +81,4 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR if (VOXELENGINE_BUILD_TESTS) enable_testing() add_subdirectory(test) -endif() +endif() \ 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 5422c873..99d2fec3 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 "assets/Assets.hpp" +#include "api_lua.hpp" #include "assets/AssetsLoader.hpp" +#include "coders/compression.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,118 @@ 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 == nullptr) { + lua::pushnil(L); + return 0; + } + + bool compress = false; + 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; + 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 + ); + } + return lua::newuserdata(L, chunk_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(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, + 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()); + } + 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 +244,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} +};