add struct Biome & move generator-related scripting to scripting_world_generation.cpp
This commit is contained in:
parent
810519fb4d
commit
685cd414c4
@ -3,6 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "scripting_commons.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "content/ContentPack.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
@ -24,7 +25,6 @@
|
||||
#include "util/timeutil.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/generator/GeneratorDef.hpp"
|
||||
|
||||
using namespace scripting;
|
||||
|
||||
@ -39,7 +39,7 @@ const ContentIndices* scripting::indices = nullptr;
|
||||
BlocksController* scripting::blocks = nullptr;
|
||||
LevelController* scripting::controller = nullptr;
|
||||
|
||||
static void load_script(const fs::path& name, bool throwable) {
|
||||
void scripting::load_script(const fs::path& name, bool throwable) {
|
||||
auto paths = scripting::engine->getPaths();
|
||||
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
|
||||
std::string src = files::read_string(file);
|
||||
@ -52,6 +52,14 @@ static void load_script(const fs::path& name, bool throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
int scripting::load_script(
|
||||
int env, const std::string& type, const fs::path& file
|
||||
) {
|
||||
std::string src = files::read_string(file);
|
||||
logger.info() << "script (" << type << ") " << file.u8string();
|
||||
return lua::execute(lua::get_main_thread(), env, src, file.u8string());
|
||||
}
|
||||
|
||||
void scripting::initialize(Engine* engine) {
|
||||
scripting::engine = engine;
|
||||
lua::initialize();
|
||||
@ -630,15 +638,6 @@ int scripting::get_values_on_stack() {
|
||||
return lua::gettop(lua::get_main_thread());
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static int load_script(
|
||||
int env, const std::string& type, const fs::path& file
|
||||
) {
|
||||
std::string src = files::read_string(file);
|
||||
logger.info() << "script (" << type << ") " << file.u8string();
|
||||
return lua::execute(lua::get_main_thread(), env, src, file.u8string());
|
||||
}
|
||||
|
||||
void scripting::load_block_script(
|
||||
const scriptenv& senv,
|
||||
const std::string& prefix,
|
||||
@ -685,155 +684,6 @@ void scripting::load_entity_component(
|
||||
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
||||
}
|
||||
|
||||
class LuaGeneratorScript : public GeneratorScript {
|
||||
scriptenv env;
|
||||
BlocksLayers groundLayers;
|
||||
BlocksLayers seaLayers;
|
||||
uint seaLevel;
|
||||
public:
|
||||
LuaGeneratorScript(
|
||||
scriptenv env,
|
||||
BlocksLayers groundLayers,
|
||||
BlocksLayers seaLayers,
|
||||
uint seaLevel)
|
||||
: env(std::move(env)),
|
||||
groundLayers(std::move(groundLayers)),
|
||||
seaLayers(std::move(seaLayers)),
|
||||
seaLevel(seaLevel)
|
||||
{}
|
||||
|
||||
std::shared_ptr<Heightmap> generateHeightmap(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed
|
||||
) override {
|
||||
auto L = lua::get_main_thread();
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::getfield(L, "generate_heightmap")) {
|
||||
lua::pushivec_stack(L, offset);
|
||||
lua::pushivec_stack(L, size);
|
||||
lua::pushinteger(L, seed);
|
||||
if (lua::call_nothrow(L, 5)) {
|
||||
auto map = lua::touserdata<lua::LuaHeightmap>(L, -1)->getHeightmap();
|
||||
lua::pop(L, 2);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
lua::pop(L);
|
||||
return std::make_shared<Heightmap>(size.x, size.y);
|
||||
}
|
||||
|
||||
void prepare(const Content* content) override {
|
||||
for (auto& layer : groundLayers.layers) {
|
||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||
}
|
||||
for (auto& layer : seaLayers.layers) {
|
||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||
}
|
||||
}
|
||||
|
||||
const BlocksLayers& getGroundLayers() const override {
|
||||
return groundLayers;
|
||||
}
|
||||
|
||||
const BlocksLayers& getSeaLayers() const override {
|
||||
return seaLayers;
|
||||
}
|
||||
|
||||
uint getSeaLevel() const override {
|
||||
return seaLevel;
|
||||
}
|
||||
};
|
||||
|
||||
static BlocksLayer load_layer(
|
||||
lua::State* L, int idx, uint& lastLayersHeight, bool& hasResizeableLayer
|
||||
) {
|
||||
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);
|
||||
bool belowSeaLevel = true;
|
||||
if (lua::getfield(L, "below_sea_level")) {
|
||||
belowSeaLevel = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
if (hasResizeableLayer) {
|
||||
lastLayersHeight += height;
|
||||
}
|
||||
if (height == -1) {
|
||||
if (hasResizeableLayer) {
|
||||
throw std::runtime_error("only one resizeable layer allowed");
|
||||
}
|
||||
hasResizeableLayer = true;
|
||||
}
|
||||
return BlocksLayer {name, height, belowSeaLevel, {}};
|
||||
}
|
||||
|
||||
static inline BlocksLayers load_layers(
|
||||
lua::State* L, const std::string& fieldname
|
||||
) {
|
||||
uint lastLayersHeight = 0;
|
||||
bool hasResizeableLayer = false;
|
||||
std::vector<BlocksLayer> layers;
|
||||
|
||||
if (lua::getfield(L, fieldname)) {
|
||||
int len = lua::objlen(L, -1);
|
||||
for (int i = 1; i <= len; i++) {
|
||||
lua::rawgeti(L, i);
|
||||
try {
|
||||
layers.push_back(
|
||||
load_layer(L, -1, lastLayersHeight, hasResizeableLayer));
|
||||
} catch (const std::runtime_error& err) {
|
||||
lua::pop(L, 2);
|
||||
throw std::runtime_error(
|
||||
fieldname+" #"+std::to_string(i)+": "+err.what());
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
return BlocksLayers {std::move(layers), lastLayersHeight};
|
||||
}
|
||||
|
||||
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||
const fs::path& file
|
||||
) {
|
||||
auto env = create_environment();
|
||||
auto L = lua::get_main_thread();
|
||||
|
||||
lua::pop(L, load_script(*env, "generator", file));
|
||||
|
||||
lua::pushenv(L, *env);
|
||||
|
||||
uint seaLevel = 0;
|
||||
if (lua::getfield(L, "sea_level")) {
|
||||
seaLevel = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
uint lastGroundLayersHeight = 0;
|
||||
uint lastSeaLayersHeight = 0;
|
||||
bool hasResizeableGroundLayer = false;
|
||||
bool hasResizeableSeaLayer = false;
|
||||
|
||||
BlocksLayers groundLayers;
|
||||
BlocksLayers seaLayers;
|
||||
try {
|
||||
groundLayers = load_layers(L, "layers");
|
||||
seaLayers = load_layers(L, "sea_layers");
|
||||
} catch (const std::runtime_error& err) {
|
||||
lua::pop(L);
|
||||
throw std::runtime_error(file.u8string()+": "+err.what());
|
||||
}
|
||||
lua::pop(L);
|
||||
return std::make_unique<LuaGeneratorScript>(
|
||||
std::move(env),
|
||||
std::move(groundLayers),
|
||||
std::move(seaLayers),
|
||||
seaLevel);
|
||||
}
|
||||
|
||||
void scripting::load_world_script(
|
||||
const scriptenv& senv,
|
||||
const std::string& prefix,
|
||||
|
||||
11
src/logic/scripting/scripting_commons.hpp
Normal file
11
src/logic/scripting/scripting_commons.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace scripting {
|
||||
void load_script(const std::filesystem::path& name, bool throwable);
|
||||
|
||||
[[nodiscard]]
|
||||
int load_script(int env, const std::string& type, const std::filesystem::path& file);
|
||||
}
|
||||
150
src/logic/scripting/scripting_world_generation.cpp
Normal file
150
src/logic/scripting/scripting_world_generation.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
#include "scripting.hpp"
|
||||
|
||||
#include "scripting_commons.hpp"
|
||||
#include "typedefs.hpp"
|
||||
#include "lua/lua_engine.hpp"
|
||||
#include "lua/lua_custom_types.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "world/generator/GeneratorDef.hpp"
|
||||
|
||||
class LuaGeneratorScript : public GeneratorScript {
|
||||
scriptenv env;
|
||||
Biome biome;
|
||||
uint seaLevel;
|
||||
public:
|
||||
LuaGeneratorScript(
|
||||
scriptenv env,
|
||||
Biome biome,
|
||||
uint seaLevel)
|
||||
: env(std::move(env)),
|
||||
biome(std::move(biome)),
|
||||
seaLevel(seaLevel)
|
||||
{}
|
||||
|
||||
std::shared_ptr<Heightmap> generateHeightmap(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed
|
||||
) override {
|
||||
auto L = lua::get_main_thread();
|
||||
lua::pushenv(L, *env);
|
||||
if (lua::getfield(L, "generate_heightmap")) {
|
||||
lua::pushivec_stack(L, offset);
|
||||
lua::pushivec_stack(L, size);
|
||||
lua::pushinteger(L, seed);
|
||||
if (lua::call_nothrow(L, 5)) {
|
||||
auto map = lua::touserdata<lua::LuaHeightmap>(L, -1)->getHeightmap();
|
||||
lua::pop(L, 2);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
lua::pop(L);
|
||||
return std::make_shared<Heightmap>(size.x, size.y);
|
||||
}
|
||||
|
||||
void prepare(const Content* content) override {
|
||||
for (auto& layer : biome.groundLayers.layers) {
|
||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||
}
|
||||
for (auto& layer : biome.seaLayers.layers) {
|
||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||
}
|
||||
}
|
||||
|
||||
const Biome& getBiome() const override {
|
||||
return biome;
|
||||
}
|
||||
|
||||
uint getSeaLevel() const override {
|
||||
return seaLevel;
|
||||
}
|
||||
};
|
||||
|
||||
static BlocksLayer load_layer(
|
||||
lua::State* L, int idx, uint& lastLayersHeight, bool& hasResizeableLayer
|
||||
) {
|
||||
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);
|
||||
bool belowSeaLevel = true;
|
||||
if (lua::getfield(L, "below_sea_level")) {
|
||||
belowSeaLevel = lua::toboolean(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
if (hasResizeableLayer) {
|
||||
lastLayersHeight += height;
|
||||
}
|
||||
if (height == -1) {
|
||||
if (hasResizeableLayer) {
|
||||
throw std::runtime_error("only one resizeable layer allowed");
|
||||
}
|
||||
hasResizeableLayer = true;
|
||||
}
|
||||
return BlocksLayer {name, height, belowSeaLevel, {}};
|
||||
}
|
||||
|
||||
static inline BlocksLayers load_layers(
|
||||
lua::State* L, const std::string& fieldname
|
||||
) {
|
||||
uint lastLayersHeight = 0;
|
||||
bool hasResizeableLayer = false;
|
||||
std::vector<BlocksLayer> layers;
|
||||
|
||||
if (lua::getfield(L, fieldname)) {
|
||||
int len = lua::objlen(L, -1);
|
||||
for (int i = 1; i <= len; i++) {
|
||||
lua::rawgeti(L, i);
|
||||
try {
|
||||
layers.push_back(
|
||||
load_layer(L, -1, lastLayersHeight, hasResizeableLayer));
|
||||
} catch (const std::runtime_error& err) {
|
||||
lua::pop(L, 2);
|
||||
throw std::runtime_error(
|
||||
fieldname+" #"+std::to_string(i)+": "+err.what());
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
lua::pop(L);
|
||||
}
|
||||
return BlocksLayers {std::move(layers), lastLayersHeight};
|
||||
}
|
||||
|
||||
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||
const fs::path& file
|
||||
) {
|
||||
auto env = create_environment();
|
||||
auto L = lua::get_main_thread();
|
||||
|
||||
lua::pop(L, load_script(*env, "generator", file));
|
||||
|
||||
lua::pushenv(L, *env);
|
||||
|
||||
uint seaLevel = 0;
|
||||
if (lua::getfield(L, "sea_level")) {
|
||||
seaLevel = lua::tointeger(L, -1);
|
||||
lua::pop(L);
|
||||
}
|
||||
|
||||
uint lastGroundLayersHeight = 0;
|
||||
uint lastSeaLayersHeight = 0;
|
||||
bool hasResizeableGroundLayer = false;
|
||||
bool hasResizeableSeaLayer = false;
|
||||
|
||||
BlocksLayers groundLayers;
|
||||
BlocksLayers seaLayers;
|
||||
try {
|
||||
groundLayers = load_layers(L, "layers");
|
||||
seaLayers = load_layers(L, "sea_layers");
|
||||
} catch (const std::runtime_error& err) {
|
||||
lua::pop(L);
|
||||
throw std::runtime_error(file.u8string()+": "+err.what());
|
||||
}
|
||||
lua::pop(L);
|
||||
return std::make_unique<LuaGeneratorScript>(
|
||||
std::move(env),
|
||||
Biome {"default", std::move(groundLayers), std::move(seaLayers)},
|
||||
seaLevel);
|
||||
}
|
||||
@ -33,6 +33,12 @@ struct BlocksLayers {
|
||||
uint lastLayersHeight;
|
||||
};
|
||||
|
||||
struct Biome {
|
||||
std::string name;
|
||||
BlocksLayers groundLayers;
|
||||
BlocksLayers seaLayers;
|
||||
};
|
||||
|
||||
/// @brief Generator behaviour and settings interface
|
||||
class GeneratorScript {
|
||||
public:
|
||||
@ -46,8 +52,7 @@ public:
|
||||
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
||||
|
||||
virtual const BlocksLayers& getGroundLayers() const = 0;
|
||||
virtual const BlocksLayers& getSeaLayers() const = 0;
|
||||
virtual const Biome& getBiome() const = 0;
|
||||
|
||||
virtual uint getSeaLevel() const = 0;
|
||||
|
||||
|
||||
@ -56,8 +56,9 @@ void WorldGenerator::generate(
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed
|
||||
);
|
||||
auto values = heightmap->getValues();
|
||||
const auto& groundLayers = def.script->getGroundLayers();
|
||||
const auto& seaLayers = def.script->getSeaLayers();
|
||||
const auto& biome = def.script->getBiome();
|
||||
const auto& groundLayers = biome.groundLayers;
|
||||
const auto& seaLayers = biome.seaLayers;
|
||||
|
||||
uint seaLevel = def.script->getSeaLevel();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user