diff --git a/res/generators/default.lua b/res/generators/default.lua index d12fd70c..41790163 100644 --- a/res/generators/default.lua +++ b/res/generators/default.lua @@ -53,6 +53,11 @@ biomes = { {block="base:stone", height=-1}, {block="base:bazalt", height=1}, }, + structures = { + "tree0", + "tree1", + "tree2" + } } } @@ -60,7 +65,7 @@ function load_structures() local structures = {} local names = {"tree0", "tree1", "tree2", "tower"} for i, name in ipairs(names) do - local filename = "core:default.files/"..name + local filename = "core:default/"..name debug.log("loading structure "..filename) table.insert(structures, generation.load_structure(filename)) end diff --git a/res/generators/default/structures.json b/res/generators/default/structures.json new file mode 100644 index 00000000..109ca95f --- /dev/null +++ b/res/generators/default/structures.json @@ -0,0 +1,6 @@ +{ + "tree0": {}, + "tree1": {}, + "tree2": {}, + "tower": {} +} diff --git a/res/generators/default.files/tower.vox b/res/generators/default/tower.vox similarity index 100% rename from res/generators/default.files/tower.vox rename to res/generators/default/tower.vox diff --git a/res/generators/default.files/tree0.vox b/res/generators/default/tree0.vox similarity index 100% rename from res/generators/default.files/tree0.vox rename to res/generators/default/tree0.vox diff --git a/res/generators/default.files/tree1.vox b/res/generators/default/tree1.vox similarity index 100% rename from res/generators/default.files/tree1.vox rename to res/generators/default/tree1.vox diff --git a/res/generators/default.files/tree2.vox b/res/generators/default/tree2.vox similarity index 100% rename from res/generators/default.files/tree2.vox rename to res/generators/default/tree2.vox diff --git a/src/content/Content.cpp b/src/content/Content.cpp index 98affbbf..68e9cec3 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -10,6 +10,7 @@ #include "objects/EntityDef.hpp" #include "objects/rigging.hpp" #include "voxels/Block.hpp" +#include "world/generator/VoxelFragment.hpp" #include "world/generator/GeneratorDef.hpp" #include "ContentPack.hpp" diff --git a/src/content/ContentBuilder.hpp b/src/content/ContentBuilder.hpp index a0daa9ac..44099304 100644 --- a/src/content/ContentBuilder.hpp +++ b/src/content/ContentBuilder.hpp @@ -8,6 +8,7 @@ #include "ContentPack.hpp" #include "items/ItemDef.hpp" #include "objects/EntityDef.hpp" +#include "world/generator/VoxelFragment.hpp" #include "world/generator/GeneratorDef.hpp" #include "voxels/Block.hpp" diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index ca4be87d..42e83fbf 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -433,18 +433,6 @@ void ContentLoader::loadEntity( if (fs::exists(configFile)) loadEntity(def, full, configFile); } - -void ContentLoader::loadGenerator( - GeneratorDef& def, const std::string& full, const std::string& name -) { - auto folder = pack->folder; - auto generatorFile = folder / fs::path("generators/" + name + ".lua"); - if (!fs::exists(generatorFile)) { - return; - } - def.script = scripting::load_generator(generatorFile); -} - void ContentLoader::loadBlock( Block& def, const std::string& full, const std::string& name ) { @@ -523,6 +511,9 @@ void ContentLoader::load() { if (fs::is_directory(generatorsDir)) { for (const auto& entry : fs::directory_iterator(generatorsDir)) { const auto& file = entry.path(); + if (fs::is_directory(file)) { + continue; + } std::string name = file.stem().u8string(); auto [packid, full, filename] = diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp new file mode 100644 index 00000000..a0f8ba49 --- /dev/null +++ b/src/content/loading/GeneratorLoader.cpp @@ -0,0 +1,74 @@ +#include "../ContentLoader.hpp" + +#include "../ContentPack.hpp" + +#include "files/files.hpp" +#include "logic/scripting/scripting.hpp" +#include "world/generator/GeneratorDef.hpp" +#include "world/generator/VoxelFragment.hpp" +#include "debug/Logger.hpp" + +static debug::Logger logger("generator-loader"); + +static VoxelStructureMeta load_structure_meta( + const std::string& name, const dv::value& config +) { + VoxelStructureMeta meta; + meta.name = name; + + return meta; +} + +static std::vector> load_structures( + const fs::path& structuresFile +) { + auto structuresDir = structuresFile.parent_path(); + auto map = files::read_json(structuresFile); + + std::vector> structures; + for (auto& [name, config] : map.asObject()) { + auto structFile = structuresDir / fs::u8path(name + ".vox"); + logger.debug() << "loading voxel fragment " << structFile.u8string(); + if (!fs::exists(structFile)) { + throw std::runtime_error("structure file does not exist (" + + structFile.u8string()); + } + auto fragment = std::make_unique(); + fragment->deserialize(files::read_binary_json(structFile)); + + structures.push_back(std::make_unique( + load_structure_meta(name, config), + std::move(fragment) + )); + } + return structures; +} + +static void load_structures(GeneratorDef& def, const fs::path& structuresFile) { + def.structures = load_structures(structuresFile); + // build indices map + for (size_t i = 0; i < def.structures.size(); i++) { + auto& structure = def.structures[i]; + def.structuresIndices[structure->meta.name] = i; + } +} + +static inline const auto STRUCTURES_FILE = fs::u8path("structures.json"); +static inline const auto GENERATORS_DIR = fs::u8path("generators"); + +void ContentLoader::loadGenerator( + GeneratorDef& def, const std::string& full, const std::string& name +) { + auto packDir = pack->folder; + auto generatorsDir = packDir / GENERATORS_DIR; + auto folder = generatorsDir / fs::u8path(name); + auto generatorFile = generatorsDir / fs::u8path(name + ".lua"); + if (!fs::exists(generatorFile)) { + return; + } + auto structuresFile = folder / STRUCTURES_FILE; + if (fs::exists(structuresFile)) { + load_structures(def, structuresFile); + } + def.script = scripting::load_generator(generatorFile); +} diff --git a/src/logic/scripting/lua/libgeneration.cpp b/src/logic/scripting/lua/libgeneration.cpp index b5e90515..2f5e4851 100644 --- a/src/logic/scripting/lua/libgeneration.cpp +++ b/src/logic/scripting/lua/libgeneration.cpp @@ -4,7 +4,7 @@ #include "files/util.hpp" #include "coders/binary_json.hpp" #include "world/Level.hpp" -#include "world/generator/VoxelStructure.hpp" +#include "world/generator/VoxelFragment.hpp" #include "engine.hpp" #include "lua_custom_types.hpp" @@ -19,7 +19,7 @@ static int l_save_structure(lua::State* L) { } bool saveEntities = lua::toboolean(L, 4); - auto structure = VoxelStructure::create(level, pointA, pointB, saveEntities); + auto structure = VoxelFragment::create(level, pointA, pointB, saveEntities); auto map = structure->serialize(); auto bytes = json::to_binary(map); @@ -37,7 +37,7 @@ static int l_load_structure(lua::State* L) { } auto map = files::read_binary_json(path); - auto structure = std::make_shared(); + auto structure = std::make_shared(); structure->deserialize(map); return lua::newuserdata(L, std::move(structure)); } diff --git a/src/logic/scripting/lua/lua_custom_types.hpp b/src/logic/scripting/lua/lua_custom_types.hpp index 79ea4492..dcd78800 100644 --- a/src/logic/scripting/lua/lua_custom_types.hpp +++ b/src/logic/scripting/lua/lua_custom_types.hpp @@ -7,7 +7,7 @@ struct fnl_state; class Heightmap; -class VoxelStructure; +class VoxelFragment; namespace lua { class Userdata { @@ -72,13 +72,13 @@ namespace lua { static_assert(!std::is_abstract()); class LuaVoxelStructure : public Userdata { - std::shared_ptr structure; + std::shared_ptr structure; public: - LuaVoxelStructure(std::shared_ptr structure); + LuaVoxelStructure(std::shared_ptr structure); virtual ~LuaVoxelStructure(); - std::shared_ptr getStructure() const { + std::shared_ptr getStructure() const { return structure; } diff --git a/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp index b35ed517..08a3ef84 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_voxelstructure.cpp @@ -2,12 +2,12 @@ #include "../lua_util.hpp" -#include "world/generator/VoxelStructure.hpp" +#include "world/generator/VoxelFragment.hpp" #include "util/stringutil.hpp" using namespace lua; -LuaVoxelStructure::LuaVoxelStructure(std::shared_ptr structure) +LuaVoxelStructure::LuaVoxelStructure(std::shared_ptr structure) : structure(std::move(structure)) {} LuaVoxelStructure::~LuaVoxelStructure() { diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index 12b4d1d5..59712dff 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -32,8 +32,8 @@ public: seaLevel(seaLevel) {} - std::vector> loadStructures() override { - std::vector> structures; + std::vector> loadStructures() override { + std::vector> structures; auto L = lua::get_main_thread(); lua::pushenv(L, *env); diff --git a/src/world/generator/GeneratorDef.cpp b/src/world/generator/GeneratorDef.cpp new file mode 100644 index 00000000..32abee49 --- /dev/null +++ b/src/world/generator/GeneratorDef.cpp @@ -0,0 +1,11 @@ +#include "GeneratorDef.hpp" + +#include "VoxelFragment.hpp" + +GeneratingVoxelStructure::GeneratingVoxelStructure( + VoxelStructureMeta meta, + std::unique_ptr structure +) : structure(std::move(structure)), meta(std::move(meta)) {} + + +GeneratorDef::GeneratorDef(std::string name) : name(std::move(name)) {} diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index 8f3c3aea..33432b09 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -1,14 +1,20 @@ #pragma once #include +#include #include +#include #include "typedefs.hpp" #include "maths/Heightmap.hpp" #include "StructurePlacement.hpp" class Content; -class VoxelStructure; +class VoxelFragment; + +struct VoxelStructureMeta { + std::string name; +}; struct BlocksLayer { /// @brief Layer block @@ -102,7 +108,7 @@ public: virtual ~GeneratorScript() = default; /// @brief Load all structures - virtual std::vector> loadStructures() = 0; + virtual std::vector> loadStructures() = 0; /// @brief Generates a heightmap with values in range 0..1 /// @param offset position of the heightmap in the world @@ -133,12 +139,25 @@ public: virtual void prepare(const Content* content) = 0; }; +struct GeneratingVoxelStructure { + VoxelStructureMeta meta; + std::unique_ptr structure; + + GeneratingVoxelStructure( + VoxelStructureMeta meta, + std::unique_ptr structure + ); +}; + /// @brief Generator information struct GeneratorDef { /// @brief Generator full name - packid:name std::string name; std::unique_ptr script; - GeneratorDef(std::string name) : name(std::move(name)) {} + std::unordered_map structuresIndices; + std::vector> structures; + + GeneratorDef(std::string name); GeneratorDef(const GeneratorDef&) = delete; }; diff --git a/src/world/generator/VoxelStructure.cpp b/src/world/generator/VoxelFragment.cpp similarity index 89% rename from src/world/generator/VoxelStructure.cpp rename to src/world/generator/VoxelFragment.cpp index 5c36176b..2dd49fb7 100644 --- a/src/world/generator/VoxelStructure.cpp +++ b/src/world/generator/VoxelFragment.cpp @@ -1,4 +1,4 @@ -#include "VoxelStructure.hpp" +#include "VoxelFragment.hpp" #include #include @@ -10,7 +10,7 @@ #include "voxels/VoxelsVolume.hpp" #include "world/Level.hpp" -std::unique_ptr VoxelStructure::create( +std::unique_ptr VoxelFragment::create( Level* level, const glm::ivec3& a, const glm::ivec3& b, bool entities ) { auto start = glm::min(a, b); @@ -43,11 +43,11 @@ std::unique_ptr VoxelStructure::create( voxels[i].state = volVoxels[i].state; } - return std::make_unique( + return std::make_unique( size, std::move(voxels), std::move(blockNames)); } -dv::value VoxelStructure::serialize() const { +dv::value VoxelFragment::serialize() const { auto root = dv::object(); root["version"] = STRUCTURE_FORMAT_VERSION; root["size"] = dv::to_value(size); @@ -64,7 +64,7 @@ dv::value VoxelStructure::serialize() const { return root; } -void VoxelStructure::deserialize(const dv::value& src) { +void VoxelFragment::deserialize(const dv::value& src) { size = glm::ivec3(); dv::get_vec(src, "size", size); @@ -83,7 +83,7 @@ void VoxelStructure::deserialize(const dv::value& src) { } } -void VoxelStructure::prepare(const Content& content) { +void VoxelFragment::prepare(const Content& content) { auto volume = size.x*size.y*size.z; voxelsRuntime.resize(volume); for (size_t i = 0; i < volume; i++) { @@ -93,7 +93,7 @@ void VoxelStructure::prepare(const Content& content) { } } -std::unique_ptr VoxelStructure::rotated(const Content& content) const { +std::unique_ptr VoxelFragment::rotated(const Content& content) const { std::vector newVoxels(voxels.size()); for (int y = 0; y < size.y; y++) { @@ -115,7 +115,7 @@ std::unique_ptr VoxelStructure::rotated(const Content& content) } } } - auto newStructure = std::make_unique( + auto newStructure = std::make_unique( // swap X and Z on 90 deg. rotation glm::ivec3(size.z, size.y, size.x), std::move(newVoxels), diff --git a/src/world/generator/VoxelStructure.hpp b/src/world/generator/VoxelFragment.hpp similarity index 85% rename from src/world/generator/VoxelStructure.hpp rename to src/world/generator/VoxelFragment.hpp index ef70c229..0a75359e 100644 --- a/src/world/generator/VoxelStructure.hpp +++ b/src/world/generator/VoxelFragment.hpp @@ -11,7 +11,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1; class Level; class Content; -class VoxelStructure : public Serializable { +class VoxelFragment : public Serializable { glm::ivec3 size; /// @brief Structure voxels indexed different to world content @@ -22,9 +22,9 @@ class VoxelStructure : public Serializable { /// @brief Structure voxels built on prepare(...) call std::vector voxelsRuntime; public: - VoxelStructure() : size() {} + VoxelFragment() : size() {} - VoxelStructure( + VoxelFragment( glm::ivec3 size, std::vector voxels, std::vector blockNames @@ -41,9 +41,9 @@ public: void prepare(const Content& content); /// @brief Create structure copy rotated 90 deg. clockwise - std::unique_ptr rotated(const Content& content) const; + std::unique_ptr rotated(const Content& content) const; - static std::unique_ptr create( + static std::unique_ptr create( Level* level, const glm::ivec3& a, const glm::ivec3& b, bool entities); const glm::ivec3& getSize() const { diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 933f2901..90778870 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -7,7 +7,7 @@ #include "voxels/Block.hpp" #include "voxels/Chunk.hpp" #include "GeneratorDef.hpp" -#include "VoxelStructure.hpp" +#include "VoxelFragment.hpp" #include "util/timeutil.hpp" #include "util/listutil.hpp" #include "debug/Logger.hpp" @@ -259,6 +259,8 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { } } } + + // TODO: put automatic placement here for (const auto& placement : prototype.structures) { if (placement.structure < 0 || placement.structure >= structures.size()) { diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index 8783bc15..29de778b 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -16,7 +16,7 @@ class Content; struct GeneratorDef; class Heightmap; struct Biome; -class VoxelStructure; +class VoxelFragment; enum class ChunkPrototypeLevel { VOID=0, BIOMES, HEIGHTMAP, STRUCTURES @@ -47,7 +47,7 @@ class WorldGenerator { /// @brief Chunk prototypes loading surround map SurroundMap surroundMap; - std::vector, 4>> structures; + std::vector, 4>> structures; /// @brief Generate chunk prototype (see ChunkPrototype) /// @param x chunk position X divided by CHUNK_W