diff --git a/res/generators/default.files/tree0.vox b/res/generators/default.files/tree0.vox new file mode 100644 index 00000000..3bcff693 Binary files /dev/null and b/res/generators/default.files/tree0.vox differ diff --git a/res/scripts/world.lua b/res/scripts/world.lua index 964100e7..d2726162 100644 --- a/res/scripts/world.lua +++ b/res/scripts/world.lua @@ -1,3 +1,4 @@ -- use for engine development tests -- must be empty in release -- must not be modified by content-packs +print(generation.load_structure("core:generators/default.files/tree0.vox")) diff --git a/src/logic/scripting/lua/libfile.cpp b/src/logic/scripting/lua/libfile.cpp index 5da4358d..30c0e204 100644 --- a/src/logic/scripting/lua/libfile.cpp +++ b/src/logic/scripting/lua/libfile.cpp @@ -158,7 +158,7 @@ static int l_file_write_bytes(lua::State* L) { fs::path path = resolve_path(lua::require_string(L, pathIndex)); - if (auto bytearray = lua::touserdata(L, -1)) { + if (auto bytearray = lua::touserdata(L, -1)) { auto& bytes = bytearray->data(); return lua::pushboolean( L, files::write_bytes(path, bytes.data(), bytes.size()) diff --git a/src/logic/scripting/lua/libgeneration.cpp b/src/logic/scripting/lua/libgeneration.cpp index 956c28e5..c38716e9 100644 --- a/src/logic/scripting/lua/libgeneration.cpp +++ b/src/logic/scripting/lua/libgeneration.cpp @@ -5,6 +5,8 @@ #include "coders/binary_json.hpp" #include "world/Level.hpp" #include "world/generator/VoxelStructure.hpp" +#include "engine.hpp" +#include "lua_custom_types.hpp" using namespace scripting; @@ -25,6 +27,21 @@ static int l_save_structure(lua::State* L) { return 0; } +static int l_load_structure(lua::State* L) { + auto paths = engine->getPaths(); + 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"); + } + auto map = files::read_binary_json(path); + + auto structure = std::make_shared(); + structure->deserialize(map); + return lua::newuserdata(L, std::move(structure)); +} + const luaL_Reg generationlib[] = { {"save_structure", lua::wrap}, + {"load_structure", lua::wrap}, {NULL, NULL}}; diff --git a/src/logic/scripting/lua/lua_custom_types.hpp b/src/logic/scripting/lua/lua_custom_types.hpp index d6a7ba0b..67faeef4 100644 --- a/src/logic/scripting/lua/lua_custom_types.hpp +++ b/src/logic/scripting/lua/lua_custom_types.hpp @@ -4,9 +4,10 @@ #include #include "lua_commons.hpp" -#include "maths/Heightmap.hpp" struct fnl_state; +class Heightmap; +class VoxelStructure; namespace lua { class Userdata { @@ -15,12 +16,12 @@ namespace lua { virtual const std::string& getTypeName() const = 0; }; - class Bytearray : public Userdata { + class LuaBytearray : public Userdata { std::vector buffer; public: - Bytearray(size_t capacity); - Bytearray(std::vector buffer); - virtual ~Bytearray(); + LuaBytearray(size_t capacity); + LuaBytearray(std::vector buffer); + virtual ~LuaBytearray(); const std::string& getTypeName() const override { return TYPENAME; @@ -32,6 +33,7 @@ namespace lua { static int createMetatable(lua::State*); inline static std::string TYPENAME = "Bytearray"; }; + static_assert(!std::is_abstract()); class LuaHeightmap : public Userdata { std::shared_ptr map; @@ -41,21 +43,13 @@ namespace lua { virtual ~LuaHeightmap(); - uint getWidth() const { - return map->getWidth(); - } + uint getWidth() const; - uint getHeight() const { - return map->getHeight(); - } + uint getHeight() const; - float* getValues() { - return map->getValues(); - } + float* getValues(); - const float* getValues() const { - return map->getValues(); - } + const float* getValues() const; const std::string& getTypeName() const override { return TYPENAME; @@ -74,4 +68,25 @@ namespace lua { static int createMetatable(lua::State*); inline static std::string TYPENAME = "Heightmap"; }; + static_assert(!std::is_abstract()); + + class LuaVoxelStructure : public Userdata { + std::shared_ptr structure; + public: + LuaVoxelStructure(std::shared_ptr structure); + + virtual ~LuaVoxelStructure(); + + std::shared_ptr getStructure() const { + return structure; + } + + const std::string& getTypeName() const override { + return TYPENAME; + } + + static int createMetatable(lua::State*); + inline static std::string TYPENAME = "VoxelStructure"; + }; + static_assert(!std::is_abstract()); } diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 879ec4c6..6ae427e3 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -96,8 +96,9 @@ void lua::initialize() { initialize_libs_extends(L); - newusertype(L, "Bytearray"); - newusertype(L, "Heightmap"); + newusertype(L); + newusertype(L); + newusertype(L); } void lua::finalize() { diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index fc202555..f365cdba 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -248,10 +248,12 @@ namespace lua { return 1; } - template - inline void newusertype(lua::State* L, const std::string& name) { + template + inline std::enable_if_t> + newusertype(lua::State* L) { + const std::string& name = T::TYPENAME; usertypeNames[typeid(T)] = name; - func(L); + T::createMetatable(L); pushcfunction(L, userdata_destructor); setfield(L, "__gc"); diff --git a/src/logic/scripting/lua/lua_type_bytearray.cpp b/src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp similarity index 81% rename from src/logic/scripting/lua/lua_type_bytearray.cpp rename to src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp index cf41f318..7be3fc10 100644 --- a/src/logic/scripting/lua/lua_type_bytearray.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp @@ -1,23 +1,23 @@ -#include "lua_custom_types.hpp" +#include "../lua_custom_types.hpp" #include -#include "lua_util.hpp" +#include "../lua_util.hpp" using namespace lua; -Bytearray::Bytearray(size_t capacity) : buffer(capacity) { +LuaBytearray::LuaBytearray(size_t capacity) : buffer(capacity) { buffer.resize(capacity); } -Bytearray::Bytearray(std::vector buffer) : buffer(std::move(buffer)) { +LuaBytearray::LuaBytearray(std::vector buffer) : buffer(std::move(buffer)) { } -Bytearray::~Bytearray() { +LuaBytearray::~LuaBytearray() { } static int l_append(lua::State* L) { - if (auto buffer = touserdata(L, 1)) { + if (auto buffer = touserdata(L, 1)) { auto value = tointeger(L, 2); buffer->data().push_back(static_cast(value)); } @@ -25,7 +25,7 @@ static int l_append(lua::State* L) { } static int l_insert(lua::State* L) { - auto buffer = touserdata(L, 1); + auto buffer = touserdata(L, 1); if (buffer == nullptr) { return 0; } @@ -40,7 +40,7 @@ static int l_insert(lua::State* L) { } static int l_remove(lua::State* L) { - auto buffer = touserdata(L, 1); + auto buffer = touserdata(L, 1); if (buffer == nullptr) { return 0; } @@ -69,17 +69,17 @@ static int l_meta_meta_call(lua::State* L) { buffer[i] = static_cast(tointeger(L, -1)); pop(L); } - return newuserdata(L, std::move(buffer)); + return newuserdata(L, std::move(buffer)); } auto size = tointeger(L, 2); if (size < 0) { throw std::runtime_error("size can not be less than 0"); } - return newuserdata(L, static_cast(size)); + return newuserdata(L, static_cast(size)); } static int l_meta_index(lua::State* L) { - auto buffer = touserdata(L, 1); + auto buffer = touserdata(L, 1); if (buffer == nullptr) { return 0; } @@ -98,7 +98,7 @@ static int l_meta_index(lua::State* L) { } static int l_meta_newindex(lua::State* L) { - auto buffer = touserdata(L, 1); + auto buffer = touserdata(L, 1); if (buffer == nullptr) { return 0; } @@ -116,14 +116,14 @@ static int l_meta_newindex(lua::State* L) { } static int l_meta_len(lua::State* L) { - if (auto buffer = touserdata(L, 1)) { + if (auto buffer = touserdata(L, 1)) { return pushinteger(L, buffer->data().size()); } return 0; } static int l_meta_tostring(lua::State* L) { - auto buffer = touserdata(L, 1); + auto buffer = touserdata(L, 1); if (buffer == nullptr) { return 0; } @@ -147,8 +147,8 @@ static int l_meta_tostring(lua::State* L) { } static int l_meta_add(lua::State* L) { - auto bufferA = touserdata(L, 1); - auto bufferB = touserdata(L, 2); + auto bufferA = touserdata(L, 1); + auto bufferB = touserdata(L, 2); if (bufferA == nullptr || bufferB == nullptr) { return 0; } @@ -159,10 +159,10 @@ static int l_meta_add(lua::State* L) { ab.reserve(dataA.size() + dataB.size()); ab.insert(ab.end(), dataA.begin(), dataA.end()); ab.insert(ab.end(), dataB.begin(), dataB.end()); - return newuserdata(L, std::move(ab)); + return newuserdata(L, std::move(ab)); } -int Bytearray::createMetatable(lua::State* L) { +int LuaBytearray::createMetatable(lua::State* L) { createtable(L, 0, 6); pushcfunction(L, lua::wrap); setfield(L, "__index"); diff --git a/src/logic/scripting/lua/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp similarity index 95% rename from src/logic/scripting/lua/lua_type_heightmap.cpp rename to src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index f467dc35..fc766c53 100644 --- a/src/logic/scripting/lua/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -1,4 +1,4 @@ -#include "lua_custom_types.hpp" +#include "../lua_custom_types.hpp" #include #include @@ -11,7 +11,8 @@ #include "coders/png.hpp" #include "files/util.hpp" #include "graphics/core/ImageData.hpp" -#include "lua_util.hpp" +#include "maths/Heightmap.hpp" +#include "../lua_util.hpp" using namespace lua; @@ -27,6 +28,22 @@ void LuaHeightmap::setSeed(int64_t seed) { noise->seed = seed; } +uint LuaHeightmap::getWidth() const { + return map->getWidth(); +} + +uint LuaHeightmap::getHeight() const { + return map->getHeight(); +} + +float* LuaHeightmap::getValues() { + return map->getValues(); +} + +const float* LuaHeightmap::getValues() const { + return map->getValues(); +} + static int l_dump(lua::State* L) { if (auto heightmap = touserdata(L, 1)) { auto filename = require_string(L, 2); diff --git a/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp new file mode 100644 index 00000000..b35ed517 --- /dev/null +++ b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp @@ -0,0 +1,26 @@ +#include "../lua_custom_types.hpp" + +#include "../lua_util.hpp" + +#include "world/generator/VoxelStructure.hpp" +#include "util/stringutil.hpp" + +using namespace lua; + +LuaVoxelStructure::LuaVoxelStructure(std::shared_ptr structure) + : structure(std::move(structure)) {} + +LuaVoxelStructure::~LuaVoxelStructure() { +} + +static int l_meta_tostring(lua::State* L) { + return pushstring(L, "VoxelStructure(0x" + util::tohex( + reinterpret_cast(topointer(L, 1)))+")"); +} + +int LuaVoxelStructure::createMetatable(lua::State* L) { + createtable(L, 0, 1); + pushcfunction(L, lua::wrap); + setfield(L, "__tostring"); + return 1; +} diff --git a/src/maths/Heightmap.hpp b/src/maths/Heightmap.hpp index 52a3d394..8e7e5594 100644 --- a/src/maths/Heightmap.hpp +++ b/src/maths/Heightmap.hpp @@ -4,6 +4,7 @@ #include #include "typedefs.hpp" +#include "maths/Heightmap.hpp" enum class InterpolationType { NEAREST, diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 4452301b..d1e5ef9f 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -312,13 +312,17 @@ std::string util::base64_encode(const ubyte* data, size_t size) { return ss.str(); } -std::string util::mangleid(uint64_t value) { - // todo: use base64 +std::string util::tohex(uint64_t value) { std::stringstream ss; ss << std::hex << value; return ss.str(); } +std::string util::mangleid(uint64_t value) { + // todo: use base64 + return tohex(value); +} + util::Buffer util::base64_decode(const char* str, size_t size) { util::Buffer bytes((size / 4) * 3); ubyte* dst = bytes.data(); diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index 21d58e5e..cb251e83 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -60,6 +60,8 @@ namespace util { util::Buffer base64_decode(const char* str, size_t size); util::Buffer base64_decode(const std::string& str); + std::string tohex(uint64_t value); + std::string mangleid(uint64_t value); int replaceAll( diff --git a/src/world/generator/VoxelStructure.cpp b/src/world/generator/VoxelStructure.cpp index 1b7abe4d..b7595064 100644 --- a/src/world/generator/VoxelStructure.cpp +++ b/src/world/generator/VoxelStructure.cpp @@ -66,11 +66,23 @@ dv::value VoxelStructure::serialize() const { void VoxelStructure::deserialize(const dv::value& src) { size = glm::ivec3(); dv::get_vec(src, "size", size); - voxels.resize(size.x*size.y*size.z); + + auto volume = size.x*size.y*size.z; + voxels.resize(volume); const auto& voxelsArr = src["voxels"]; - for (size_t i = 0; i < size.x*size.y*size.z; i++) { + for (size_t i = 0; i < volume; i++) { voxels[i].id = voxelsArr[i * 2].asInteger(); voxels[i].state = int2blockstate(voxelsArr[i * 2 + 1].asInteger()); } } + +void VoxelStructure::prepare(const Content& content) { + auto volume = size.x*size.y*size.z; + voxelsRuntime.resize(volume); + for (size_t i = 0; i < volume; i++) { + const auto& name = blockNames[voxels[i].id]; + voxelsRuntime[i].id = content.blocks.require(name).rt.id; + voxelsRuntime[i].state = voxels[i].state; + } +} diff --git a/src/world/generator/VoxelStructure.hpp b/src/world/generator/VoxelStructure.hpp index 68819653..444a1f1a 100644 --- a/src/world/generator/VoxelStructure.hpp +++ b/src/world/generator/VoxelStructure.hpp @@ -11,7 +11,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1; class Level; class Content; -struct VoxelStructure : public Serializable { +class VoxelStructure : public Serializable { glm::ivec3 size; /// @brief Structure voxels indexed different to world content @@ -19,6 +19,9 @@ struct VoxelStructure : public Serializable { /// @brief Block names are used for indexing std::vector blockNames; + /// @brief Structure voxels built on prepare(...) call + std::vector voxelsRuntime; +public: VoxelStructure() : size() {} VoxelStructure( @@ -33,6 +36,18 @@ struct VoxelStructure : public Serializable { dv::value serialize() const override; void deserialize(const dv::value& src) override; + /// @brief Build runtime voxel indices + /// @param content world content + void prepare(const Content& content); + static std::unique_ptr create( Level* level, const glm::ivec3& a, const glm::ivec3& b, bool entities); + + const glm::ivec3& getSize() const { + return size; + } + + const std::vector& getRuntimeVoxels() { + return voxelsRuntime; + } }; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index a6a1fe7e..726467a0 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -7,7 +7,8 @@ #include "content/Content.hpp" #include "voxels/Block.hpp" #include "voxels/Chunk.hpp" -#include "world/generator/GeneratorDef.hpp" +#include "GeneratorDef.hpp" +#include "VoxelStructure.hpp" #include "util/timeutil.hpp" #include "debug/Logger.hpp" @@ -47,6 +48,8 @@ WorldGenerator::WorldGenerator( }); } +WorldGenerator::~WorldGenerator() {} + static inline void generate_pole( const BlocksLayers& layers, int top, int bottom, @@ -119,8 +122,8 @@ std::unique_ptr WorldGenerator::generatePrototype( } return std::make_unique( ChunkPrototypeLevel::BIOMES, - nullptr, - std::move(chunkBiomes)); + std::move(chunkBiomes), + nullptr); } void WorldGenerator::generateHeightmap( diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index 2802baa6..d30d88f9 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -14,6 +14,7 @@ class Content; struct GeneratorDef; class Heightmap; struct Biome; +class VoxelStructure; enum class ChunkPrototypeLevel { BIOMES, HEIGHTMAP @@ -22,18 +23,19 @@ enum class ChunkPrototypeLevel { struct ChunkPrototype { ChunkPrototypeLevel level; - /// @brief chunk heightmap - std::shared_ptr heightmap; /// @brief chunk biomes matrix std::vector biomes; + /// @brief chunk heightmap + std::shared_ptr heightmap; + ChunkPrototype( ChunkPrototypeLevel level, - std::shared_ptr heightmap, - std::vector biomes + std::vector biomes, + std::shared_ptr heightmap ) : level(level), - heightmap(std::move(heightmap)), - biomes(std::move(biomes)) {}; + biomes(std::move(biomes)), + heightmap(std::move(heightmap)) {}; }; /// @brief High-level world generation controller @@ -49,6 +51,8 @@ class WorldGenerator { /// @brief Chunk prototypes loading surround map SurroundMap surroundMap; + std::vector> structures; + /// @brief Generate chunk prototype (see ChunkPrototype) /// @param x chunk position X divided by CHUNK_W /// @param z chunk position Y divided by CHUNK_D @@ -61,15 +65,15 @@ public: const Content* content, uint64_t seed ); - virtual ~WorldGenerator() = default; + ~WorldGenerator(); - virtual void update(int centerX, int centerY, int loadDistance); + void update(int centerX, int centerY, int loadDistance); /// @brief Generate complete chunk voxels /// @param voxels destinatiopn chunk voxels buffer /// @param x chunk position X divided by CHUNK_W /// @param z chunk position Y divided by CHUNK_D - virtual void generate(voxel* voxels, int x, int z); + void generate(voxel* voxels, int x, int z); inline static std::string DEFAULT = "core:default"; };