add generator layers
This commit is contained in:
parent
30925df319
commit
2a767a3638
@ -1,3 +1,10 @@
|
|||||||
|
layers = {
|
||||||
|
{block="base:grass_block", height=1},
|
||||||
|
{block="base:dirt", height=1},
|
||||||
|
{block="base:stone", height=-1},
|
||||||
|
{block="base:bazalt", height=1},
|
||||||
|
}
|
||||||
|
|
||||||
function generate_heightmap(x, y, w, h)
|
function generate_heightmap(x, y, w, h)
|
||||||
local umap = Heightmap(w, h)
|
local umap = Heightmap(w, h)
|
||||||
local vmap = Heightmap(w, h)
|
local vmap = Heightmap(w, h)
|
||||||
|
|||||||
@ -88,5 +88,9 @@ std::unique_ptr<Content> ContentBuilder::build() {
|
|||||||
def->rt.placingBlock = content->blocks.require(def->placingBlock).rt.id;
|
def->rt.placingBlock = content->blocks.require(def->placingBlock).rt.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& [name, def] : content->generators.getDefs()) {
|
||||||
|
def->script->prepare(content.get());
|
||||||
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -473,7 +473,11 @@ void ContentLoader::load() {
|
|||||||
|
|
||||||
auto& def = builder.generators.create(full);
|
auto& def = builder.generators.create(full);
|
||||||
|
|
||||||
loadGenerator(def, full, name);
|
try {
|
||||||
|
loadGenerator(def, full, name);
|
||||||
|
} catch (const std::runtime_error& err) {
|
||||||
|
throw std::runtime_error("generator '"+full+"': "+err.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -496,17 +496,26 @@ namespace lua {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int pushvalue(lua::State*, const dynamic::Value& value);
|
int pushvalue(lua::State*, const dynamic::Value& value);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
dynamic::Value tovalue(lua::State*, int idx);
|
dynamic::Value tovalue(lua::State*, int idx);
|
||||||
|
|
||||||
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
|
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
|
||||||
lua_getfield(L, idx, name.c_str());
|
lua_getfield(L, idx, name.c_str());
|
||||||
if (isnil(L, -1)) {
|
if (isnil(L, idx)) {
|
||||||
pop(L);
|
pop(L);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int requirefield(lua::State* L, const std::string& name, int idx = -1) {
|
||||||
|
if (getfield(L, name, idx)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
throw std::runtime_error("object has no member '"+name+"'");
|
||||||
|
}
|
||||||
|
|
||||||
inline bool hasfield(lua::State* L, const std::string& name, int idx = -1) {
|
inline bool hasfield(lua::State* L, const std::string& name, int idx = -1) {
|
||||||
lua_getfield(L, idx, name.c_str());
|
lua_getfield(L, idx, name.c_str());
|
||||||
if (isnil(L, -1)) {
|
if (isnil(L, -1)) {
|
||||||
|
|||||||
@ -686,8 +686,11 @@ void scripting::load_entity_component(
|
|||||||
|
|
||||||
class LuaGeneratorScript : public GeneratorScript {
|
class LuaGeneratorScript : public GeneratorScript {
|
||||||
scriptenv env;
|
scriptenv env;
|
||||||
|
std::vector<BlocksLayer> layers;
|
||||||
|
uint lastLayersHeight;
|
||||||
public:
|
public:
|
||||||
LuaGeneratorScript(scriptenv env) : env(std::move(env)) {}
|
LuaGeneratorScript(scriptenv env, std::vector<BlocksLayer> layers, uint lastLayersHeight)
|
||||||
|
: env(std::move(env)), layers(std::move(layers)), lastLayersHeight(lastLayersHeight) {}
|
||||||
|
|
||||||
std::shared_ptr<Heightmap> generateHeightmap(
|
std::shared_ptr<Heightmap> generateHeightmap(
|
||||||
const glm::ivec2& offset, const glm::ivec2& size
|
const glm::ivec2& offset, const glm::ivec2& size
|
||||||
@ -706,6 +709,20 @@ public:
|
|||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
return std::make_shared<Heightmap>(size.x, size.y);
|
return std::make_shared<Heightmap>(size.x, size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void prepare(const Content* content) override {
|
||||||
|
for (auto& layer : layers) {
|
||||||
|
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<BlocksLayer>& getLayers() const override {
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getLastLayersHeight() const override {
|
||||||
|
return lastLayersHeight;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||||
@ -713,7 +730,46 @@ std::unique_ptr<GeneratorScript> scripting::load_generator(
|
|||||||
) {
|
) {
|
||||||
auto env = create_environment();
|
auto env = create_environment();
|
||||||
load_script(*env, "generator", file);
|
load_script(*env, "generator", file);
|
||||||
return std::make_unique<LuaGeneratorScript>(std::move(env));
|
|
||||||
|
auto L = lua::get_main_thread();
|
||||||
|
lua::pushenv(L, *env);
|
||||||
|
|
||||||
|
uint lastLayersHeight = 0;
|
||||||
|
bool hasResizeableLayer = false;
|
||||||
|
|
||||||
|
std::vector<BlocksLayer> layers;
|
||||||
|
if (lua::getfield(L, "layers")) {
|
||||||
|
int len = lua::objlen(L, -1);
|
||||||
|
for (int i = 1; i <= len; i++) {
|
||||||
|
try {
|
||||||
|
lua::rawgeti(L, i);
|
||||||
|
lua::requirefield(L, "block");
|
||||||
|
auto name = lua::require_string(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
lua::requirefield(L, "height");
|
||||||
|
int height = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L, 2);
|
||||||
|
|
||||||
|
if (hasResizeableLayer) {
|
||||||
|
lastLayersHeight += height;
|
||||||
|
}
|
||||||
|
if (height == -1) {
|
||||||
|
if (hasResizeableLayer) {
|
||||||
|
throw std::runtime_error("only one resizeable layer allowed");
|
||||||
|
}
|
||||||
|
hasResizeableLayer = true;
|
||||||
|
}
|
||||||
|
layers.push_back(BlocksLayer {name, height, {}});
|
||||||
|
} catch (const std::runtime_error& err) {
|
||||||
|
lua::pop(L, 2);
|
||||||
|
throw std::runtime_error(
|
||||||
|
"layer #"+std::to_string(i)+": "+err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
return std::make_unique<LuaGeneratorScript>(std::move(env), std::move(layers), lastLayersHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::load_world_script(
|
void scripting::load_world_script(
|
||||||
|
|||||||
@ -6,12 +6,30 @@
|
|||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "maths/Heightmap.hpp"
|
#include "maths/Heightmap.hpp"
|
||||||
|
|
||||||
|
class Content;
|
||||||
|
|
||||||
|
struct BlocksLayer {
|
||||||
|
std::string block;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
blockid_t id;
|
||||||
|
} rt;
|
||||||
|
};
|
||||||
|
|
||||||
class GeneratorScript {
|
class GeneratorScript {
|
||||||
public:
|
public:
|
||||||
virtual ~GeneratorScript() = default;
|
virtual ~GeneratorScript() = default;
|
||||||
|
|
||||||
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
||||||
const glm::ivec2& offset, const glm::ivec2& size) = 0;
|
const glm::ivec2& offset, const glm::ivec2& size) = 0;
|
||||||
|
|
||||||
|
virtual const std::vector<BlocksLayer>& getLayers() const = 0;
|
||||||
|
|
||||||
|
/// @brief Total height of all layers after resizeable one
|
||||||
|
virtual uint getLastLayersHeight() const = 0;
|
||||||
|
|
||||||
|
virtual void prepare(const Content* content) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GeneratorDef {
|
struct GeneratorDef {
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "WorldGenerator.hpp"
|
#include "WorldGenerator.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
@ -14,21 +16,32 @@ WorldGenerator::WorldGenerator(
|
|||||||
|
|
||||||
#include "util/timeutil.hpp"
|
#include "util/timeutil.hpp"
|
||||||
void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ, int seed) {
|
void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ, int seed) {
|
||||||
timeutil::ScopeLogTimer log(555);
|
|
||||||
auto heightmap = def.script->generateHeightmap(
|
auto heightmap = def.script->generateHeightmap(
|
||||||
{chunkX*CHUNK_W, chunkZ*CHUNK_D}, {CHUNK_W, CHUNK_D}
|
{chunkX*CHUNK_W, chunkZ*CHUNK_D}, {CHUNK_W, CHUNK_D}
|
||||||
);
|
);
|
||||||
auto& baseStone = content->blocks.require("base:stone");
|
timeutil::ScopeLogTimer log(555);
|
||||||
auto& baseWater = content->blocks.require("base:water");
|
auto values = heightmap->getValues();
|
||||||
|
const auto& layers = def.script->getLayers();
|
||||||
|
uint lastLayersHeight = def.script->getLastLayersHeight();
|
||||||
|
auto baseWater = content->blocks.require("base:water").rt.id;
|
||||||
|
|
||||||
|
std::memset(voxels, 0, sizeof(voxel) * CHUNK_VOL);
|
||||||
|
|
||||||
for (uint z = 0; z < CHUNK_D; z++) {
|
for (uint z = 0; z < CHUNK_D; z++) {
|
||||||
for (uint x = 0; x < CHUNK_W; x++) {
|
for (uint x = 0; x < CHUNK_W; x++) {
|
||||||
auto height = heightmap->getValues()[z * CHUNK_W + x] * 255 + 10;
|
int height = values[z * CHUNK_W + x] * 255 + 10;
|
||||||
for (uint y = 0; y < CHUNK_H; y++) {
|
for (uint y = height+1; y < 64; y++) {
|
||||||
voxels[vox_index(x, y, z)].state = {};
|
voxels[vox_index(x, y, z)].id = baseWater;
|
||||||
if (y > height) {
|
}
|
||||||
voxels[vox_index(x, y, z)].id = y <= 64 ? baseWater.rt.id : 0;
|
|
||||||
} else {
|
uint y = height;
|
||||||
voxels[vox_index(x, y, z)].id = baseStone.rt.id;
|
for (const auto& layer : layers) {
|
||||||
|
uint layerHeight = layer.height;
|
||||||
|
if (layerHeight == -1) {
|
||||||
|
layerHeight = y - lastLayersHeight + 1;
|
||||||
|
}
|
||||||
|
for (uint i = 0; i < layerHeight; i++, y--) {
|
||||||
|
voxels[vox_index(x, y, z)].id = layer.rt.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user