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 <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "scripting_commons.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
#include "content/ContentPack.hpp"
|
#include "content/ContentPack.hpp"
|
||||||
#include "debug/Logger.hpp"
|
#include "debug/Logger.hpp"
|
||||||
@ -24,7 +25,6 @@
|
|||||||
#include "util/timeutil.hpp"
|
#include "util/timeutil.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "world/generator/GeneratorDef.hpp"
|
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ const ContentIndices* scripting::indices = nullptr;
|
|||||||
BlocksController* scripting::blocks = nullptr;
|
BlocksController* scripting::blocks = nullptr;
|
||||||
LevelController* scripting::controller = 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();
|
auto paths = scripting::engine->getPaths();
|
||||||
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
|
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
|
||||||
std::string src = files::read_string(file);
|
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) {
|
void scripting::initialize(Engine* engine) {
|
||||||
scripting::engine = engine;
|
scripting::engine = engine;
|
||||||
lua::initialize();
|
lua::initialize();
|
||||||
@ -630,15 +638,6 @@ int scripting::get_values_on_stack() {
|
|||||||
return lua::gettop(lua::get_main_thread());
|
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(
|
void scripting::load_block_script(
|
||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
@ -685,155 +684,6 @@ void scripting::load_entity_component(
|
|||||||
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
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(
|
void scripting::load_world_script(
|
||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
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;
|
uint lastLayersHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Biome {
|
||||||
|
std::string name;
|
||||||
|
BlocksLayers groundLayers;
|
||||||
|
BlocksLayers seaLayers;
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Generator behaviour and settings interface
|
/// @brief Generator behaviour and settings interface
|
||||||
class GeneratorScript {
|
class GeneratorScript {
|
||||||
public:
|
public:
|
||||||
@ -46,8 +52,7 @@ public:
|
|||||||
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
||||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0;
|
||||||
|
|
||||||
virtual const BlocksLayers& getGroundLayers() const = 0;
|
virtual const Biome& getBiome() const = 0;
|
||||||
virtual const BlocksLayers& getSeaLayers() const = 0;
|
|
||||||
|
|
||||||
virtual uint getSeaLevel() 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
|
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed
|
||||||
);
|
);
|
||||||
auto values = heightmap->getValues();
|
auto values = heightmap->getValues();
|
||||||
const auto& groundLayers = def.script->getGroundLayers();
|
const auto& biome = def.script->getBiome();
|
||||||
const auto& seaLayers = def.script->getSeaLayers();
|
const auto& groundLayers = biome.groundLayers;
|
||||||
|
const auto& seaLayers = biome.seaLayers;
|
||||||
|
|
||||||
uint seaLevel = def.script->getSeaLevel();
|
uint seaLevel = def.script->getSeaLevel();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user