refactor & add structures.json

This commit is contained in:
MihailRis 2024-09-24 04:05:13 +03:00
parent 519ebc05f1
commit 323c2f2935
20 changed files with 153 additions and 43 deletions

View File

@ -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

View File

@ -0,0 +1,6 @@
{
"tree0": {},
"tree1": {},
"tree2": {},
"tower": {}
}

View File

@ -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"

View File

@ -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"

View File

@ -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] =

View File

@ -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<std::unique_ptr<GeneratingVoxelStructure>> load_structures(
const fs::path& structuresFile
) {
auto structuresDir = structuresFile.parent_path();
auto map = files::read_json(structuresFile);
std::vector<std::unique_ptr<GeneratingVoxelStructure>> 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<VoxelFragment>();
fragment->deserialize(files::read_binary_json(structFile));
structures.push_back(std::make_unique<GeneratingVoxelStructure>(
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);
}

View File

@ -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<VoxelStructure>();
auto structure = std::make_shared<VoxelFragment>();
structure->deserialize(map);
return lua::newuserdata<lua::LuaVoxelStructure>(L, std::move(structure));
}

View File

@ -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<LuaHeightmap>());
class LuaVoxelStructure : public Userdata {
std::shared_ptr<VoxelStructure> structure;
std::shared_ptr<VoxelFragment> structure;
public:
LuaVoxelStructure(std::shared_ptr<VoxelStructure> structure);
LuaVoxelStructure(std::shared_ptr<VoxelFragment> structure);
virtual ~LuaVoxelStructure();
std::shared_ptr<VoxelStructure> getStructure() const {
std::shared_ptr<VoxelFragment> getStructure() const {
return structure;
}

View File

@ -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<VoxelStructure> structure)
LuaVoxelStructure::LuaVoxelStructure(std::shared_ptr<VoxelFragment> structure)
: structure(std::move(structure)) {}
LuaVoxelStructure::~LuaVoxelStructure() {

View File

@ -32,8 +32,8 @@ public:
seaLevel(seaLevel)
{}
std::vector<std::shared_ptr<VoxelStructure>> loadStructures() override {
std::vector<std::shared_ptr<VoxelStructure>> structures;
std::vector<std::shared_ptr<VoxelFragment>> loadStructures() override {
std::vector<std::shared_ptr<VoxelFragment>> structures;
auto L = lua::get_main_thread();
lua::pushenv(L, *env);

View File

@ -0,0 +1,11 @@
#include "GeneratorDef.hpp"
#include "VoxelFragment.hpp"
GeneratingVoxelStructure::GeneratingVoxelStructure(
VoxelStructureMeta meta,
std::unique_ptr<VoxelFragment> structure
) : structure(std::move(structure)), meta(std::move(meta)) {}
GeneratorDef::GeneratorDef(std::string name) : name(std::move(name)) {}

View File

@ -1,14 +1,20 @@
#pragma once
#include <string>
#include <vector>
#include <glm/glm.hpp>
#include <unordered_map>
#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<std::shared_ptr<VoxelStructure>> loadStructures() = 0;
virtual std::vector<std::shared_ptr<VoxelFragment>> 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<VoxelFragment> structure;
GeneratingVoxelStructure(
VoxelStructureMeta meta,
std::unique_ptr<VoxelFragment> structure
);
};
/// @brief Generator information
struct GeneratorDef {
/// @brief Generator full name - packid:name
std::string name;
std::unique_ptr<GeneratorScript> script;
GeneratorDef(std::string name) : name(std::move(name)) {}
std::unordered_map<std::string, size_t> structuresIndices;
std::vector<std::unique_ptr<GeneratingVoxelStructure>> structures;
GeneratorDef(std::string name);
GeneratorDef(const GeneratorDef&) = delete;
};

View File

@ -1,4 +1,4 @@
#include "VoxelStructure.hpp"
#include "VoxelFragment.hpp"
#include <unordered_map>
#include <cstring>
@ -10,7 +10,7 @@
#include "voxels/VoxelsVolume.hpp"
#include "world/Level.hpp"
std::unique_ptr<VoxelStructure> VoxelStructure::create(
std::unique_ptr<VoxelFragment> 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> VoxelStructure::create(
voxels[i].state = volVoxels[i].state;
}
return std::make_unique<VoxelStructure>(
return std::make_unique<VoxelFragment>(
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> VoxelStructure::rotated(const Content& content) const {
std::unique_ptr<VoxelFragment> VoxelFragment::rotated(const Content& content) const {
std::vector<voxel> newVoxels(voxels.size());
for (int y = 0; y < size.y; y++) {
@ -115,7 +115,7 @@ std::unique_ptr<VoxelStructure> VoxelStructure::rotated(const Content& content)
}
}
}
auto newStructure = std::make_unique<VoxelStructure>(
auto newStructure = std::make_unique<VoxelFragment>(
// swap X and Z on 90 deg. rotation
glm::ivec3(size.z, size.y, size.x),
std::move(newVoxels),

View File

@ -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<voxel> voxelsRuntime;
public:
VoxelStructure() : size() {}
VoxelFragment() : size() {}
VoxelStructure(
VoxelFragment(
glm::ivec3 size,
std::vector<voxel> voxels,
std::vector<std::string> blockNames
@ -41,9 +41,9 @@ public:
void prepare(const Content& content);
/// @brief Create structure copy rotated 90 deg. clockwise
std::unique_ptr<VoxelStructure> rotated(const Content& content) const;
std::unique_ptr<VoxelFragment> rotated(const Content& content) const;
static std::unique_ptr<VoxelStructure> create(
static std::unique_ptr<VoxelFragment> create(
Level* level, const glm::ivec3& a, const glm::ivec3& b, bool entities);
const glm::ivec3& getSize() const {

View File

@ -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"
@ -260,6 +260,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()) {
logger.error() << "invalid structure index " << placement.structure;

View File

@ -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<std::array<std::shared_ptr<VoxelStructure>, 4>> structures;
std::vector<std::array<std::shared_ptr<VoxelFragment>, 4>> structures;
/// @brief Generate chunk prototype (see ChunkPrototype)
/// @param x chunk position X divided by CHUNK_W