From f1f81371affec4e1f5f8fe69c84e8cc50dc1e3f6 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 19 Jan 2025 23:36:37 +0300 Subject: [PATCH] add world.save_chunk_data(...) --- src/logic/scripting/lua/libs/libworld.cpp | 22 ++++++++++++ src/voxels/compressed_chunks.cpp | 44 +++++++++++++++++++---- src/voxels/compressed_chunks.hpp | 2 ++ 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index bbba422df..5db150b0d 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -6,6 +6,7 @@ #include "assets/AssetsLoader.hpp" #include "coders/json.hpp" #include "engine/Engine.hpp" +#include "files/WorldFiles.hpp" #include "files/engine_paths.hpp" #include "files/files.hpp" #include "lighting/Lighting.hpp" @@ -158,9 +159,14 @@ static void integrate_chunk_client(Chunk& chunk) { } static int l_set_chunk_data(lua::State* L) { + if (level == nullptr) { + throw std::runtime_error("no open world"); + } + int x = static_cast(lua::tointeger(L, 1)); int z = static_cast(lua::tointeger(L, 2)); auto buffer = lua::require_bytearray(L, 3); + auto chunk = level->chunks->getChunk(x, z); if (chunk == nullptr) { return lua::pushboolean(L, false); @@ -175,6 +181,21 @@ static int l_set_chunk_data(lua::State* L) { return lua::pushboolean(L, true); } +static int l_save_chunk_data(lua::State* L) { + if (level == nullptr) { + throw std::runtime_error("no open world"); + } + + int x = static_cast(lua::tointeger(L, 1)); + int z = static_cast(lua::tointeger(L, 2)); + auto buffer = lua::require_bytearray(L, 3); + + compressed_chunks::save( + x, z, std::move(buffer), level->getWorld()->wfile->getRegions() + ); + return 0; +} + static int l_count_chunks(lua::State* L) { if (level == nullptr) { return 0; @@ -197,6 +218,7 @@ const luaL_Reg worldlib[] = { {"exists", lua::wrap}, {"get_chunk_data", lua::wrap}, {"set_chunk_data", lua::wrap}, + {"save_chunk_data", lua::wrap}, {"count_chunks", lua::wrap}, {NULL, NULL} }; diff --git a/src/voxels/compressed_chunks.cpp b/src/voxels/compressed_chunks.cpp index 0e6772af8..64000a79a 100644 --- a/src/voxels/compressed_chunks.cpp +++ b/src/voxels/compressed_chunks.cpp @@ -3,6 +3,7 @@ #include "coders/rle.hpp" #include "coders/gzip.hpp" #include "coders/byte_utils.hpp" +#include "files/WorldFiles.hpp" #include "voxels/Chunk.hpp" inline constexpr int HAS_VOXELS = 0x1; @@ -34,6 +35,15 @@ std::vector compressed_chunks::encode(const Chunk& chunk) { return builder.build(); } +static void read_voxel_data(ByteReader& reader, util::Buffer& dst) { + size_t gzipCompressedSize = reader.getInt32(); + + auto rleData = gzip::decompress(reader.pointer(), gzipCompressedSize); + reader.skip(gzipCompressedSize); + + extrle::decode16(rleData.data(), rleData.size(), dst.data()); +} + void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) { ByteReader reader(src, size); @@ -41,14 +51,9 @@ void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) { 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()); + read_voxel_data(reader, voxelData); chunk.decode(voxelData.data()); chunk.updateHeights(); } @@ -59,3 +64,30 @@ void compressed_chunks::decode(Chunk& chunk, const ubyte* src, size_t size) { } chunk.setModifiedAndUnsaved(); } + +void compressed_chunks::save( + int x, int z, std::vector bytes, WorldRegions& regions +) { + ByteReader reader(bytes.data(), bytes.size()); + + ubyte flags = reader.get(); + reader.skip(1); // reserved byte + if (flags & HAS_VOXELS) { + util::Buffer voxelData (CHUNK_DATA_LEN); + read_voxel_data(reader, voxelData); + regions.put( + x, z, REGION_LAYER_VOXELS, voxelData.release(), CHUNK_DATA_LEN + ); + } + if (flags & HAS_METADATA) { + size_t metadataSize = reader.getInt32(); + regions.put( + x, + z, + REGION_LAYER_BLOCKS_DATA, + util::Buffer(reader.pointer(), metadataSize).release(), + metadataSize + ); + reader.skip(metadataSize); + } +} diff --git a/src/voxels/compressed_chunks.hpp b/src/voxels/compressed_chunks.hpp index dc0bc5b6a..2181669cd 100644 --- a/src/voxels/compressed_chunks.hpp +++ b/src/voxels/compressed_chunks.hpp @@ -5,8 +5,10 @@ #include class Chunk; +class WorldRegions; namespace compressed_chunks { std::vector encode(const Chunk& chunk); void decode(Chunk& chunk, const ubyte* src, size_t size); + void save(int x, int z, std::vector bytes, WorldRegions& regions); }