add generator definition file (.toml)
This commit is contained in:
parent
d839da7dab
commit
3d478aef08
4
res/content/base/generators/demo.toml
Normal file
4
res/content/base/generators/demo.toml
Normal file
@ -0,0 +1,4 @@
|
||||
# 1 - temperature
|
||||
# 2 - humidity
|
||||
biome_parameters = 2
|
||||
sea_level = 64
|
||||
@ -1,9 +1,3 @@
|
||||
sea_level = 64
|
||||
|
||||
-- 1 - temperature
|
||||
-- 2 - humidity
|
||||
biome_parameters = 2
|
||||
|
||||
biomes = json.parse(file.read("base:generators/demo/biomes.json"))
|
||||
|
||||
function place_structures(x, z, w, d, seed, hmap)
|
||||
1
res/generators/default.toml
Normal file
1
res/generators/default.toml
Normal file
@ -0,0 +1 @@
|
||||
biome_parameters = 0
|
||||
@ -1,5 +1,3 @@
|
||||
biome_parameters = 0
|
||||
|
||||
biomes = {flat = {
|
||||
parameters = {},
|
||||
layers = {
|
||||
@ -9,7 +7,3 @@ biomes = {flat = {
|
||||
{height=-1, block="core:obstacle"}
|
||||
}
|
||||
}}
|
||||
|
||||
function generate_heightmap(x, y, w, h, seed)
|
||||
return Heightmap(w, h)
|
||||
end
|
||||
@ -49,7 +49,7 @@ static void detect_defs(
|
||||
if (name[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
if (fs::is_regular_file(file) && file.extension() == ".json") {
|
||||
if (fs::is_regular_file(file) && files::is_data_file(file)) {
|
||||
detected.push_back(prefix.empty() ? name : prefix + ":" + name);
|
||||
} else if (fs::is_directory(file)) {
|
||||
detect_defs(file, name, detected);
|
||||
|
||||
@ -66,14 +66,20 @@ void ContentLoader::loadGenerator(
|
||||
) {
|
||||
auto packDir = pack->folder;
|
||||
auto generatorsDir = packDir / GENERATORS_DIR;
|
||||
auto folder = generatorsDir / fs::u8path(name);
|
||||
auto generatorFile = generatorsDir / fs::u8path(name + ".lua");
|
||||
auto generatorFile = generatorsDir / fs::u8path(name + ".toml");
|
||||
if (!fs::exists(generatorFile)) {
|
||||
return;
|
||||
}
|
||||
auto map = files::read_toml(generatorsDir / fs::u8path(name + ".toml"));
|
||||
map.at("biome_parameters").get(def.biomeParameters);
|
||||
map.at("sea_level").get(def.seaLevel);
|
||||
|
||||
auto folder = generatorsDir / fs::u8path(name);
|
||||
auto scriptFile = folder / fs::u8path("script.lua");
|
||||
|
||||
auto structuresFile = folder / STRUCTURES_FILE;
|
||||
if (fs::exists(structuresFile)) {
|
||||
load_structures(def, structuresFile);
|
||||
}
|
||||
def.script = scripting::load_generator(generatorFile);
|
||||
def.script = scripting::load_generator(def, scriptFile);
|
||||
}
|
||||
|
||||
@ -159,3 +159,36 @@ std::vector<std::string> files::read_list(const fs::path& filename) {
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/toml.hpp"
|
||||
|
||||
using DecodeFunc = dv::value(*)(std::string_view, std::string_view);
|
||||
|
||||
static std::map<fs::path, DecodeFunc> data_decoders {
|
||||
{fs::u8path(".json"), json::parse},
|
||||
{fs::u8path(".toml"), toml::parse},
|
||||
};
|
||||
|
||||
bool files::is_data_file(const fs::path& file) {
|
||||
return is_data_interchange_format(file.extension());
|
||||
}
|
||||
|
||||
bool files::is_data_interchange_format(const fs::path& ext) {
|
||||
return data_decoders.find(ext) != data_decoders.end();
|
||||
}
|
||||
|
||||
dv::value files::read_object(const fs::path& file) {
|
||||
const auto& found = data_decoders.find(file.extension());
|
||||
if (found == data_decoders.end()) {
|
||||
throw std::runtime_error("unknown file format");
|
||||
}
|
||||
auto text = read_string(file);
|
||||
try {
|
||||
return found->second(file.u8string(), text);
|
||||
} catch (const parsing_error& err) {
|
||||
throw std::runtime_error(err.errorLog());
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,4 +66,8 @@ namespace files {
|
||||
dv::value read_binary_json(const fs::path& file);
|
||||
dv::value read_toml(const fs::path& file);
|
||||
std::vector<std::string> read_list(const fs::path& file);
|
||||
|
||||
bool is_data_file(const fs::path& file);
|
||||
bool is_data_interchange_format(const fs::path& ext);
|
||||
dv::value read_object(const fs::path& file);
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ class LevelController;
|
||||
class Entity;
|
||||
struct EntityDef;
|
||||
class GeneratorScript;
|
||||
struct GeneratorDef;
|
||||
|
||||
namespace scripting {
|
||||
extern Engine* engine;
|
||||
@ -147,6 +148,7 @@ namespace scripting {
|
||||
void load_entity_component(const std::string& name, const fs::path& file);
|
||||
|
||||
std::unique_ptr<GeneratorScript> load_generator(
|
||||
const GeneratorDef& def,
|
||||
const fs::path& file
|
||||
);
|
||||
|
||||
|
||||
@ -16,20 +16,17 @@
|
||||
#include "util/timeutil.hpp"
|
||||
|
||||
class LuaGeneratorScript : public GeneratorScript {
|
||||
const GeneratorDef& def;
|
||||
scriptenv env;
|
||||
std::vector<Biome> biomes;
|
||||
uint biomeParameters;
|
||||
uint seaLevel;
|
||||
public:
|
||||
LuaGeneratorScript(
|
||||
scriptenv env,
|
||||
std::vector<Biome> biomes,
|
||||
uint biomeParameters,
|
||||
uint seaLevel)
|
||||
: env(std::move(env)),
|
||||
biomes(std::move(biomes)),
|
||||
biomeParameters(biomeParameters),
|
||||
seaLevel(seaLevel)
|
||||
const GeneratorDef& def,
|
||||
scriptenv env,
|
||||
std::vector<Biome> biomes)
|
||||
: def(def),
|
||||
env(std::move(env)),
|
||||
biomes(std::move(biomes))
|
||||
{}
|
||||
|
||||
std::shared_ptr<Heightmap> generateHeightmap(
|
||||
@ -56,6 +53,7 @@ public:
|
||||
) override {
|
||||
std::vector<std::shared_ptr<Heightmap>> maps;
|
||||
|
||||
uint biomeParameters = def.biomeParameters;
|
||||
auto L = lua::get_main_thread();
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::getfield(L, "generate_biome_parameters")) {
|
||||
@ -79,7 +77,6 @@ public:
|
||||
}
|
||||
|
||||
std::vector<StructurePlacement> placeStructures(
|
||||
const GeneratorDef& def,
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed,
|
||||
const std::shared_ptr<Heightmap>& heightmap
|
||||
) override {
|
||||
@ -153,14 +150,6 @@ public:
|
||||
const std::vector<Biome>& getBiomes() const override {
|
||||
return biomes;
|
||||
}
|
||||
|
||||
uint getBiomeParameters() const override {
|
||||
return biomeParameters;
|
||||
}
|
||||
|
||||
uint getSeaLevel() const override {
|
||||
return seaLevel;
|
||||
}
|
||||
};
|
||||
|
||||
static BlocksLayer load_layer(
|
||||
@ -273,7 +262,7 @@ static inline Biome load_biome(
|
||||
}
|
||||
|
||||
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||
const fs::path& file
|
||||
const GeneratorDef& def, const fs::path& file
|
||||
) {
|
||||
auto env = create_environment();
|
||||
auto L = lua::get_main_thread();
|
||||
@ -285,24 +274,20 @@ std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||
auto root = lua::tovalue(L, -1);
|
||||
lua::pop(L);
|
||||
|
||||
uint biomeParameters = root["biome_parameters"].asInteger();
|
||||
uint seaLevel = 0;
|
||||
root.at("sea_level").get(seaLevel);
|
||||
|
||||
std::vector<Biome> biomes;
|
||||
|
||||
const auto& biomesMap = root["biomes"];
|
||||
for (const auto& [biomeName, biomeMap] : biomesMap.asObject()) {
|
||||
try {
|
||||
biomes.push_back(
|
||||
load_biome(biomeMap, biomeName, biomeParameters, -2));
|
||||
load_biome(biomeMap, biomeName, def.biomeParameters, -2));
|
||||
} catch (const std::runtime_error& err) {
|
||||
throw std::runtime_error("biome "+biomeName+": "+err.what());
|
||||
}
|
||||
}
|
||||
return std::make_unique<LuaGeneratorScript>(
|
||||
def,
|
||||
std::move(env),
|
||||
std::move(biomes),
|
||||
biomeParameters,
|
||||
seaLevel);
|
||||
std::move(biomes)
|
||||
);
|
||||
}
|
||||
|
||||
@ -135,19 +135,12 @@ public:
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
||||
|
||||
virtual std::vector<StructurePlacement> placeStructures(
|
||||
const GeneratorDef& def,
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed,
|
||||
const std::shared_ptr<Heightmap>& heightmap) = 0;
|
||||
|
||||
/// @brief Get generator biomes
|
||||
virtual const std::vector<Biome>& getBiomes() const = 0;
|
||||
|
||||
/// @return Number of biome parameters, that biome choosing depending on
|
||||
virtual uint getBiomeParameters() const = 0;
|
||||
|
||||
/// @return Sea level (top of seaLayers)
|
||||
virtual uint getSeaLevel() const = 0;
|
||||
|
||||
/// @brief Build the runtime cache
|
||||
/// @param content built content
|
||||
virtual void prepare(const GeneratorDef& def, const Content* content) = 0;
|
||||
@ -169,6 +162,12 @@ struct GeneratorDef {
|
||||
std::string name;
|
||||
std::unique_ptr<GeneratorScript> script;
|
||||
|
||||
/// @brief Sea level (top of seaLayers)
|
||||
uint seaLevel = 0;
|
||||
|
||||
/// @brief Number of biome parameters, that biome choosing depending on
|
||||
uint biomeParameters = 0;
|
||||
|
||||
std::unordered_map<std::string, size_t> structuresIndices;
|
||||
std::vector<std::unique_ptr<GeneratingVoxelStructure>> structures;
|
||||
|
||||
|
||||
@ -175,7 +175,7 @@ void WorldGenerator::generateStructures(
|
||||
const auto& heightmap = prototype.heightmap;
|
||||
|
||||
util::concat(prototype.structures, def.script->placeStructures(
|
||||
def, {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed,
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed,
|
||||
heightmap
|
||||
));
|
||||
for (const auto& placement : prototype.structures) {
|
||||
@ -202,7 +202,7 @@ void WorldGenerator::generateStructures(
|
||||
}
|
||||
uint8_t rotation = structsRand.randU32() % 4;
|
||||
int height = heights[z * CHUNK_W + x] * CHUNK_H;
|
||||
if (height < def.script->getSeaLevel()) {
|
||||
if (height < def.seaLevel) {
|
||||
continue;
|
||||
}
|
||||
auto& structure = *def.structures[structureId]->fragments[rotation];
|
||||
@ -268,7 +268,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
||||
const auto& prototype = requirePrototype(chunkX, chunkZ);
|
||||
const auto values = prototype.heightmap->getValues();
|
||||
|
||||
uint seaLevel = def.script->getSeaLevel();
|
||||
uint seaLevel = def.seaLevel;
|
||||
|
||||
std::memset(voxels, 0, sizeof(voxel) * CHUNK_VOL);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user