diff --git a/res/content/base/generators/demo.files/fragments/tower.vox b/res/content/base/generators/demo.files/fragments/tower.vox index c992fe45..a6b58857 100644 Binary files a/res/content/base/generators/demo.files/fragments/tower.vox and b/res/content/base/generators/demo.files/fragments/tower.vox differ diff --git a/res/content/base/generators/demo.files/fragments/tree0.vox b/res/content/base/generators/demo.files/fragments/tree0.vox index 74cbcc3f..78e87cbf 100644 Binary files a/res/content/base/generators/demo.files/fragments/tree0.vox and b/res/content/base/generators/demo.files/fragments/tree0.vox differ diff --git a/res/content/base/generators/demo.files/fragments/tree1.vox b/res/content/base/generators/demo.files/fragments/tree1.vox index 7dda751d..6c2aec44 100644 Binary files a/res/content/base/generators/demo.files/fragments/tree1.vox and b/res/content/base/generators/demo.files/fragments/tree1.vox differ diff --git a/res/content/base/generators/demo.files/fragments/tree2.vox b/res/content/base/generators/demo.files/fragments/tree2.vox index 98fc3bef..0aac534c 100644 Binary files a/res/content/base/generators/demo.files/fragments/tree2.vox and b/res/content/base/generators/demo.files/fragments/tree2.vox differ diff --git a/res/scripts/stdcmd.lua b/res/scripts/stdcmd.lua index ef742d5e..a2edd9b8 100644 --- a/res/scripts/stdcmd.lua +++ b/res/scripts/stdcmd.lua @@ -174,3 +174,16 @@ console.add_command( " has been saved as "..file.resolve(filename)) end ) + +console.add_command( + "fragment.crop filename:str", + "Crop fragment", + function(args, kwargs) + local filename = args[1] + local fragment = generation.load_fragment(filename) + fragment:crop() + generation.save_fragment(fragment, filename, crop) + console.log("fragment with size "..vec3.tostring(fragment.size).. + " has been saved as "..file.resolve(filename)) + end +) diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 54b9b288..ec8315f5 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -145,6 +145,9 @@ static std::vector> load_structures( } auto fragment = std::make_unique(); fragment->deserialize(files::read_binary_json(structFile)); + logger.info() << "fragment " << name << " has size [" << + fragment->getSize().x << ", " << fragment->getSize().y << ", " << + fragment->getSize().z << "]"; structures.push_back(std::make_unique( load_structure_meta(name, config), diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 2874dbad..ca97815c 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -36,9 +36,8 @@ static int l_create_fragment(lua::State* L) { static int l_load_fragment(lua::State* L) { auto paths = engine->getPaths(); - auto [prefix, filename] = EnginePaths::parsePath(lua::require_string(L, 1)); - - auto path = paths->resolve(prefix+":generators/"+filename+".vox"); + auto filename = lua::require_string(L, 1); + auto path = paths->resolve(filename); if (!std::filesystem::exists(path)) { throw std::runtime_error("file "+path.u8string()+" does not exist"); } diff --git a/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp index fd40ee83..eb6a24ab 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp @@ -13,6 +13,17 @@ LuaVoxelFragment::LuaVoxelFragment(std::shared_ptr fragment) LuaVoxelFragment::~LuaVoxelFragment() { } +static int l_crop(lua::State* L) { + if (auto fragment = touserdata(L, 1)) { + fragment->getFragment()->crop(); + } + return 0; +} + +static std::unordered_map methods { + {"crop", lua::wrap}, +}; + static int l_meta_tostring(lua::State* L) { return pushstring(L, "VoxelFragment(0x" + util::tohex( reinterpret_cast(topointer(L, 1)))+")"); @@ -27,12 +38,16 @@ static int l_meta_index(lua::State* L) { auto fieldname = tostring(L, 2); if (!std::strcmp(fieldname, "size")) { return pushivec(L, fragment->getFragment()->getSize()); + } else { + auto found = methods.find(tostring(L, 2)); + if (found != methods.end()) { + return pushcfunction(L, found->second); + } } } return 0; } - int LuaVoxelFragment::createMetatable(lua::State* L) { createtable(L, 0, 2); pushcfunction(L, lua::wrap); diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index 75925a38..75b37b9e 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -108,10 +108,10 @@ void ChunksStorage::getVoxels(VoxelsVolume* volume, bool backlight) const { int ecz = floordiv(z + d, CHUNK_D); int cw = ecx - scx + 1; - int ch = ecz - scz + 1; + int cd = ecz - scz + 1; - // cw*ch chunks will be scanned - for (int cz = scz; cz < scz + ch; cz++) { + // cw*cd chunks will be scanned + for (int cz = scz; cz < scz + cd; cz++) { for (int cx = scx; cx < scx + cw; cx++) { const auto& found = chunksMap.find(glm::ivec2(cx, cz)); if (found == chunksMap.end()) { diff --git a/src/world/generator/VoxelFragment.cpp b/src/world/generator/VoxelFragment.cpp index 5289051b..96191725 100644 --- a/src/world/generator/VoxelFragment.cpp +++ b/src/world/generator/VoxelFragment.cpp @@ -9,6 +9,7 @@ #include "voxels/ChunksStorage.hpp" #include "voxels/VoxelsVolume.hpp" #include "world/Level.hpp" +#include "core_defs.hpp" std::unique_ptr VoxelFragment::create( Level* level, @@ -51,10 +52,10 @@ std::unique_ptr VoxelFragment::create( level->chunksStorage->getVoxels(&volume); auto volVoxels = volume.getVoxels(); - std::vector voxels(size.x*size.y*size.z); + std::vector voxels(size.x * size.y * size.z); - std::vector blockNames; - std::unordered_map blocksRegistered; + std::vector blockNames {CORE_AIR}; + std::unordered_map blocksRegistered {{0, 0}}; auto contentIndices = level->content->getIndices(); for (size_t i = 0 ; i < voxels.size(); i++) { blockid_t id = volVoxels[i].id; @@ -113,6 +114,49 @@ void VoxelFragment::deserialize(const dv::value& src) { } } +void VoxelFragment::crop() { + glm::ivec3 min = size; + glm::ivec3 max = {}; + + blockid_t air; + const auto& found = std::find(blockNames.begin(), blockNames.end(), CORE_AIR); + if (found == blockNames.end()) { + throw std::runtime_error(CORE_AIR+" is not found in fragment"); + } + air = found - blockNames.begin(); + + for (int y = 0; y < size.y; y++) { + for (int z = 0; z < size.z; z++) { + for (int x = 0; x < size.x; x++) { + if (voxels[vox_index(x, y, z, size.x, size.z)].id != air) { + min = glm::min(min, {x, y, z}); + max = glm::max(max, {x+1, y+1, z+1}); + } + } + } + } + if (glm::min(min, max) == min) { + auto newSize = max - min; + std::vector newVoxels(newSize.x * newSize.y * newSize.z); + for (int y = 0; y < newSize.y; y++) { + for (int z = 0; z < newSize.z; z++) { + for (int x = 0; x < newSize.x; x++) { + newVoxels[vox_index(x, y, z, newSize.x, newSize.z)] = + voxels[vox_index( + x + min.x, + y + min.y, + z + min.z, + size.x, + size.z + )]; + } + } + } + voxels = std::move(newVoxels); + size = newSize; + } +} + void VoxelFragment::prepare(const Content& content) { auto volume = size.x*size.y*size.z; voxelsRuntime.resize(volume); @@ -129,8 +173,8 @@ std::unique_ptr VoxelFragment::rotated(const Content& content) co for (int y = 0; y < size.y; y++) { for (int z = 0; z < size.z; z++) { for (int x = 0; x < size.x; x++) { - auto& voxel = newVoxels[vox_index(x, y, z, size.x, size.z)]; - voxel = voxels[vox_index(size.z-z-1, y, x, size.z, size.x)]; + auto& voxel = newVoxels[vox_index(size.z-z-1, y, x, size.z, size.x)]; + voxel = voxels[vox_index(x, y, z, size.x, size.z)]; // swap X and Z segment bits voxel.state.segment = ((voxel.state.segment & 0b001) << 2) | (voxel.state.segment & 0b010) diff --git a/src/world/generator/VoxelFragment.hpp b/src/world/generator/VoxelFragment.hpp index f9e94ab8..95a5375b 100644 --- a/src/world/generator/VoxelFragment.hpp +++ b/src/world/generator/VoxelFragment.hpp @@ -35,6 +35,7 @@ public: dv::value serialize() const override; void deserialize(const dv::value& src) override; + void crop(); /// @brief Build runtime voxel indices /// @param content world content diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 0f79c4e8..b0236ec2 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -272,9 +272,6 @@ void WorldGenerator::generateStructures( glm::ivec3 position {x, height, z}; position.x -= structure.getSize().x / 2; position.z -= structure.getSize().z / 2; - prototype.placements.emplace_back( - 1, StructurePlacement {structureId, position, rotation} - ); placeStructure( StructurePlacement { structureId, @@ -486,6 +483,7 @@ void WorldGenerator::generateStructure( auto& structVoxels = structure.getRuntimeVoxels(); const auto& offset = placement.position; const auto& size = structure.getSize(); + for (int y = 0; y < size.y; y++) { int sy = y + offset.y; if (sy < 0 || sy >= CHUNK_H) { diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index c6f37fa1..fa8a51e0 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -66,10 +66,6 @@ class WorldGenerator { void generateStructures(ChunkPrototype& prototype, int x, int z); - void generatePlacements( - const ChunkPrototype& prototype, voxel* voxels, int x, int z - ); - void generateBiomes(ChunkPrototype& prototype, int x, int z); void generateHeightmap(ChunkPrototype& prototype, int x, int z); @@ -81,6 +77,9 @@ class WorldGenerator { void placeLine(const LinePlacement& line, int priority); + void generatePlacements( + const ChunkPrototype& prototype, voxel* voxels, int x, int z + ); void generateLine( const ChunkPrototype& prototype, const LinePlacement& placement, @@ -113,7 +112,8 @@ class WorldGenerator { void placeStructures( const std::vector& placements, ChunkPrototype& prototype, - int x, int z); + int x, int z + ); public: WorldGenerator( const GeneratorDef& def,