add automatic biome-based structures placement
This commit is contained in:
parent
323c2f2935
commit
806ed4b155
@ -53,10 +53,11 @@ biomes = {
|
|||||||
{block="base:stone", height=-1},
|
{block="base:stone", height=-1},
|
||||||
{block="base:bazalt", height=1},
|
{block="base:bazalt", height=1},
|
||||||
},
|
},
|
||||||
|
structure_chance = 0.032,
|
||||||
structures = {
|
structures = {
|
||||||
"tree0",
|
{name="tree0", weight=1},
|
||||||
"tree1",
|
{name="tree1", weight=1},
|
||||||
"tree2"
|
{name="tree2", weight=1},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,24 +75,6 @@ end
|
|||||||
|
|
||||||
function place_structures(x, z, w, d, seed, hmap)
|
function place_structures(x, z, w, d, seed, hmap)
|
||||||
local placements = {}
|
local placements = {}
|
||||||
for i=0,math.floor(math.random()*3)+5 do
|
|
||||||
local px = math.random() * w
|
|
||||||
local pz = math.random() * d
|
|
||||||
local py = hmap:at(px, pz) * 256
|
|
||||||
if py <= sea_level then
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
table.insert(placements,
|
|
||||||
{math.floor(math.random() * 3), {px-8, py, pz-8}, math.floor(math.random()*4)})
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
if math.random() < 0.01 then
|
|
||||||
local px = math.random() * w
|
|
||||||
local pz = math.random() * d
|
|
||||||
local py = hmap:at(px, pz) * 256
|
|
||||||
table.insert(placements, {3, {px-8, py, pz-8}, 0})
|
|
||||||
end
|
|
||||||
return placements
|
return placements
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,7 @@ std::unique_ptr<Content> ContentBuilder::build() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [name, def] : content->generators.getDefs()) {
|
for (auto& [name, def] : content->generators.getDefs()) {
|
||||||
def->script->prepare(content.get());
|
def->script->prepare(*def, content.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
|
|||||||
@ -45,7 +45,12 @@ static std::vector<std::unique_ptr<GeneratingVoxelStructure>> load_structures(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void load_structures(GeneratorDef& def, const fs::path& structuresFile) {
|
static void load_structures(GeneratorDef& def, const fs::path& structuresFile) {
|
||||||
def.structures = load_structures(structuresFile);
|
auto rawStructures = load_structures(structuresFile);
|
||||||
|
def.structures.resize(rawStructures.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < rawStructures.size(); i++) {
|
||||||
|
def.structures[i] = std::move(rawStructures[i]);
|
||||||
|
}
|
||||||
// build indices map
|
// build indices map
|
||||||
for (size_t i = 0; i < def.structures.size(); i++) {
|
for (size_t i = 0; i < def.structures.size(); i++) {
|
||||||
auto& structure = def.structures[i];
|
auto& structure = def.structures[i];
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#include "voxels/Chunk.hpp"
|
#include "voxels/Chunk.hpp"
|
||||||
#include "data/dv.hpp"
|
#include "data/dv.hpp"
|
||||||
#include "world/generator/GeneratorDef.hpp"
|
#include "world/generator/GeneratorDef.hpp"
|
||||||
|
#include "util/stringutil.hpp"
|
||||||
#include "util/timeutil.hpp"
|
#include "util/timeutil.hpp"
|
||||||
|
|
||||||
class LuaGeneratorScript : public GeneratorScript {
|
class LuaGeneratorScript : public GeneratorScript {
|
||||||
@ -140,7 +140,7 @@ public:
|
|||||||
return placements;
|
return placements;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare(const Content* content) override {
|
void prepare(const GeneratorDef& def, const Content* content) override {
|
||||||
for (auto& biome : biomes) {
|
for (auto& biome : biomes) {
|
||||||
for (auto& layer : biome.groundLayers.layers) {
|
for (auto& layer : biome.groundLayers.layers) {
|
||||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||||
@ -148,8 +148,16 @@ public:
|
|||||||
for (auto& layer : biome.seaLayers.layers) {
|
for (auto& layer : biome.seaLayers.layers) {
|
||||||
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
layer.rt.id = content->blocks.require(layer.block).rt.id;
|
||||||
}
|
}
|
||||||
for (auto& plant : biome.plants.plants) {
|
for (auto& plant : biome.plants.entries) {
|
||||||
plant.rt.id = content->blocks.require(plant.block).rt.id;
|
plant.rt.id = content->blocks.require(plant.name).rt.id;
|
||||||
|
}
|
||||||
|
for (auto& structure : biome.structures.entries) {
|
||||||
|
const auto& found = def.structuresIndices.find(structure.name);
|
||||||
|
if (found == def.structuresIndices.end()) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"no structure "+util::quote(structure.name)+" found");
|
||||||
|
}
|
||||||
|
structure.rt.id = found->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,29 +215,36 @@ static inline BlocksLayers load_layers(
|
|||||||
return BlocksLayers {std::move(layers), lastLayersHeight};
|
return BlocksLayers {std::move(layers), lastLayersHeight};
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BiomePlants load_plants(
|
static inline BiomeElementList load_biome_element_list(
|
||||||
const dv::value& biomeMap
|
const dv::value map,
|
||||||
|
const std::string& chanceName,
|
||||||
|
const std::string& arrName,
|
||||||
|
const std::string& nameName
|
||||||
) {
|
) {
|
||||||
float plantChance = 0.0f;
|
float chance = 0.0f;
|
||||||
biomeMap.at("plant_chance").get(plantChance);
|
map.at(chanceName).get(chance);
|
||||||
float plantsWeightSum = 0.0f;
|
std::vector<WeightedEntry> entries;
|
||||||
|
if (map.has(arrName)) {
|
||||||
std::vector<PlantEntry> plants;
|
const auto& arr = map[arrName];
|
||||||
if (biomeMap.has("plants")) {
|
for (const auto& entry : arr) {
|
||||||
const auto& plantsArr = biomeMap["plants"];
|
const auto& name = entry[nameName].asString();
|
||||||
for (const auto& entry : plantsArr) {
|
|
||||||
const auto& block = entry["block"].asString();
|
|
||||||
float weight = entry["weight"].asNumber();
|
float weight = entry["weight"].asNumber();
|
||||||
if (weight <= 0.0f) {
|
if (weight <= 0.0f) {
|
||||||
throw std::runtime_error("weight must be positive");
|
throw std::runtime_error("weight must be positive");
|
||||||
}
|
}
|
||||||
plantsWeightSum += weight;
|
entries.push_back(WeightedEntry {name, weight, {}});
|
||||||
plants.push_back(PlantEntry {block, weight, {}});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(plants.begin(), plants.end(), std::greater<PlantEntry>());
|
std::sort(entries.begin(), entries.end(), std::greater<WeightedEntry>());
|
||||||
return BiomePlants {
|
return BiomeElementList(std::move(entries), chance);
|
||||||
std::move(plants), plantsWeightSum, plantChance};
|
}
|
||||||
|
|
||||||
|
static inline BiomeElementList load_plants(const dv::value& biomeMap) {
|
||||||
|
return load_biome_element_list(biomeMap, "plant_chance", "plants", "block");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BiomeElementList load_structures(const dv::value map) {
|
||||||
|
return load_biome_element_list(map, "structure_chance", "structures", "name");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Biome load_biome(
|
static inline Biome load_biome(
|
||||||
@ -252,13 +267,19 @@ static inline Biome load_biome(
|
|||||||
parameters.push_back(BiomeParameter {value, weight});
|
parameters.push_back(BiomeParameter {value, weight});
|
||||||
}
|
}
|
||||||
|
|
||||||
BiomePlants plants = load_plants(biomeMap);
|
auto plants = load_plants(biomeMap);
|
||||||
BlocksLayers groundLayers = load_layers(biomeMap["layers"], "layers");
|
auto groundLayers = load_layers(biomeMap["layers"], "layers");
|
||||||
BlocksLayers seaLayers = load_layers(biomeMap["sea_layers"], "sea_layers");
|
auto seaLayers = load_layers(biomeMap["sea_layers"], "sea_layers");
|
||||||
|
|
||||||
|
BiomeElementList structures;
|
||||||
|
if (biomeMap.has("structures")) {
|
||||||
|
structures = load_structures(biomeMap);
|
||||||
|
}
|
||||||
return Biome {
|
return Biome {
|
||||||
name,
|
name,
|
||||||
std::move(parameters),
|
std::move(parameters),
|
||||||
std::move(plants),
|
std::move(plants),
|
||||||
|
std::move(structures),
|
||||||
std::move(groundLayers),
|
std::move(groundLayers),
|
||||||
std::move(seaLayers)};
|
std::move(seaLayers)};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
GeneratingVoxelStructure::GeneratingVoxelStructure(
|
GeneratingVoxelStructure::GeneratingVoxelStructure(
|
||||||
VoxelStructureMeta meta,
|
VoxelStructureMeta meta,
|
||||||
std::unique_ptr<VoxelFragment> structure
|
std::unique_ptr<VoxelFragment> structure
|
||||||
) : structure(std::move(structure)), meta(std::move(meta)) {}
|
) : fragments({std::move(structure)}), meta(std::move(meta)) {}
|
||||||
|
|
||||||
|
|
||||||
GeneratorDef::GeneratorDef(std::string name) : name(std::move(name)) {}
|
GeneratorDef::GeneratorDef(std::string name) : name(std::move(name)) {}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
@ -11,6 +12,7 @@
|
|||||||
|
|
||||||
class Content;
|
class Content;
|
||||||
class VoxelFragment;
|
class VoxelFragment;
|
||||||
|
struct GeneratorDef;
|
||||||
|
|
||||||
struct VoxelStructureMeta {
|
struct VoxelStructureMeta {
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -49,56 +51,70 @@ struct BiomeParameter {
|
|||||||
float weight;
|
float weight;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Plant is a single-block structure randomly generating in world
|
struct WeightedEntry {
|
||||||
struct PlantEntry {
|
std::string name;
|
||||||
/// @brief Plant block id
|
|
||||||
std::string block;
|
|
||||||
/// @brief Plant weight
|
|
||||||
float weight;
|
float weight;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
blockid_t id;
|
size_t id;
|
||||||
} rt;
|
} rt;
|
||||||
|
|
||||||
bool operator>(const PlantEntry& other) const {
|
bool operator>(const WeightedEntry& other) const {
|
||||||
return weight > other.weight;
|
return weight > other.weight;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BiomePlants {
|
struct BiomeElementList {
|
||||||
static inline float MIN_CHANCE = 0.000001f;
|
static inline float MIN_CHANCE = 0.000001f;
|
||||||
|
|
||||||
/// @brief Plant entries sorted by weight descending.
|
/// @brief Entries sorted by weight descending.
|
||||||
std::vector<PlantEntry> plants;
|
std::vector<WeightedEntry> entries;
|
||||||
/// @brief Sum of weight values
|
/// @brief Sum of weight values
|
||||||
float weightsSum;
|
float weightsSum;
|
||||||
/// @brief Plant generation chance
|
/// @brief Value generation chance
|
||||||
float chance;
|
float chance;
|
||||||
|
|
||||||
/// @brief Choose plant based on weight
|
BiomeElementList() {}
|
||||||
|
|
||||||
|
BiomeElementList(std::vector<WeightedEntry> entries, float chance)
|
||||||
|
: entries(entries), chance(chance) {
|
||||||
|
for (const auto& entry : entries) {
|
||||||
|
weightsSum += entry.weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Choose value based on weight
|
||||||
/// @param rand some random value in range [0, 1)
|
/// @param rand some random value in range [0, 1)
|
||||||
/// @return index of chosen plant block
|
/// @return *.index of chosen value
|
||||||
inline blockid_t choose(float rand) const {
|
inline size_t choose(float rand, size_t def=0) const {
|
||||||
if (plants.empty() || rand > chance || chance < MIN_CHANCE) {
|
if (entries.empty() || rand > chance || chance < MIN_CHANCE) {
|
||||||
return 0;
|
return def;
|
||||||
}
|
}
|
||||||
rand = rand / chance;
|
rand = rand / chance;
|
||||||
rand *= weightsSum;
|
rand *= weightsSum;
|
||||||
for (const auto& plant : plants) {
|
for (const auto& entry : entries) {
|
||||||
rand -= plant.weight;
|
rand -= entry.weight;
|
||||||
if (rand <= 0.0f) {
|
if (rand <= 0.0f) {
|
||||||
return plant.rt.id;
|
return entry.rt.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return plants[plants.size()-1].rt.id;
|
return entries[entries.size()-1].rt.id;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Biome {
|
struct Biome {
|
||||||
|
/// @brief Biome name
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
std::vector<BiomeParameter> parameters;
|
std::vector<BiomeParameter> parameters;
|
||||||
BiomePlants plants;
|
|
||||||
|
/// @brief Plant is a single-block structure randomly generating in world
|
||||||
|
BiomeElementList plants;
|
||||||
|
|
||||||
|
BiomeElementList structures;
|
||||||
|
|
||||||
BlocksLayers groundLayers;
|
BlocksLayers groundLayers;
|
||||||
|
|
||||||
BlocksLayers seaLayers;
|
BlocksLayers seaLayers;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -136,12 +152,12 @@ public:
|
|||||||
|
|
||||||
/// @brief Build the runtime cache
|
/// @brief Build the runtime cache
|
||||||
/// @param content built content
|
/// @param content built content
|
||||||
virtual void prepare(const Content* content) = 0;
|
virtual void prepare(const GeneratorDef& def, const Content* content) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GeneratingVoxelStructure {
|
struct GeneratingVoxelStructure {
|
||||||
VoxelStructureMeta meta;
|
VoxelStructureMeta meta;
|
||||||
std::unique_ptr<VoxelFragment> structure;
|
std::array<std::unique_ptr<VoxelFragment>, 4> fragments;
|
||||||
|
|
||||||
GeneratingVoxelStructure(
|
GeneratingVoxelStructure(
|
||||||
VoxelStructureMeta meta,
|
VoxelStructureMeta meta,
|
||||||
|
|||||||
@ -49,15 +49,12 @@ WorldGenerator::WorldGenerator(
|
|||||||
generateStructures(requirePrototype(x, z), x, z);
|
generateStructures(requirePrototype(x, z), x, z);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto rawStructures = def.script->loadStructures();
|
for (int i = 0; i < def.structures.size(); i++) {
|
||||||
structures.resize(rawStructures.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < rawStructures.size(); i++) {
|
|
||||||
structures[i][0] = std::move(rawStructures[i]);
|
|
||||||
structures[i][0]->prepare(*content);
|
|
||||||
// pre-calculate rotated structure variants
|
// pre-calculate rotated structure variants
|
||||||
|
def.structures[i]->fragments[0]->prepare(*content);
|
||||||
for (int j = 1; j < 4; j++) {
|
for (int j = 1; j < 4; j++) {
|
||||||
structures[i][j] = structures[i][j-1]->rotated(*content);
|
def.structures[i]->fragments[j] =
|
||||||
|
def.structures[i]->fragments[j-1]->rotated(*content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,44 +137,89 @@ inline AABB gen_chunk_aabb(int chunkX, int chunkZ) {
|
|||||||
{(chunkX + 1)*CHUNK_W, 256, (chunkZ + 1) * CHUNK_D});
|
{(chunkX + 1)*CHUNK_W, 256, (chunkZ + 1) * CHUNK_D});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldGenerator::placeStructure(
|
||||||
|
const glm::ivec3 offset, size_t structureId, uint8_t rotation,
|
||||||
|
int chunkX, int chunkZ
|
||||||
|
) {
|
||||||
|
auto& structure = *def.structures[structureId]->fragments[rotation];
|
||||||
|
auto position = glm::ivec3(chunkX * CHUNK_W, 0, chunkZ * CHUNK_D)+offset;
|
||||||
|
auto size = structure.getSize() + glm::ivec3(0, CHUNK_H, 0);
|
||||||
|
AABB aabb(position, position + size);
|
||||||
|
for (int lcz = -1; lcz <= 1; lcz++) {
|
||||||
|
for (int lcx = -1; lcx <= 1; lcx++) {
|
||||||
|
if (lcx == 0 && lcz == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto& otherPrototype = requirePrototype(
|
||||||
|
chunkX + lcx, chunkZ + lcz
|
||||||
|
);
|
||||||
|
auto chunkAABB = gen_chunk_aabb(chunkX + lcx, chunkZ + lcz);
|
||||||
|
if (chunkAABB.intersect(aabb)) {
|
||||||
|
otherPrototype.structures.emplace_back(
|
||||||
|
structureId,
|
||||||
|
offset -
|
||||||
|
glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D),
|
||||||
|
rotation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WorldGenerator::generateStructures(
|
void WorldGenerator::generateStructures(
|
||||||
ChunkPrototype& prototype, int chunkX, int chunkZ
|
ChunkPrototype& prototype, int chunkX, int chunkZ
|
||||||
) {
|
) {
|
||||||
if (prototype.level >= ChunkPrototypeLevel::STRUCTURES) {
|
if (prototype.level >= ChunkPrototypeLevel::STRUCTURES) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto& biomes = prototype.biomes;
|
||||||
|
const auto& heightmap = prototype.heightmap;
|
||||||
|
const auto& heights = heightmap->getValues();
|
||||||
|
|
||||||
util::concat(prototype.structures, def.script->placeStructures(
|
util::concat(prototype.structures, def.script->placeStructures(
|
||||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed,
|
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed,
|
||||||
prototype.heightmap
|
heightmap
|
||||||
));
|
));
|
||||||
for (const auto& placement : prototype.structures) {
|
for (const auto& placement : prototype.structures) {
|
||||||
const auto& offset = placement.position;
|
const auto& offset = placement.position;
|
||||||
if (placement.structure < 0 || placement.structure >= structures.size()) {
|
if (placement.structure < 0 || placement.structure >= def.structures.size()) {
|
||||||
logger.error() << "invalid structure index " << placement.structure;
|
logger.error() << "invalid structure index " << placement.structure;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto& structure = *structures[placement.structure][placement.rotation];
|
placeStructure(
|
||||||
auto position = glm::ivec3(chunkX * CHUNK_W, 0, chunkZ * CHUNK_D)+offset;
|
offset, placement.structure, placement.rotation, chunkX, chunkZ);
|
||||||
auto size = structure.getSize() + glm::ivec3(0, CHUNK_H, 0);
|
}
|
||||||
AABB aabb(position, position + size);
|
|
||||||
for (int lcz = -1; lcz <= 1; lcz++) {
|
PseudoRandom structsRand;
|
||||||
for (int lcx = -1; lcx <= 1; lcx++) {
|
structsRand.setSeed(chunkX, chunkZ);
|
||||||
if (lcx == 0 && lcz == 0) {
|
|
||||||
continue;
|
for (uint z = 0; z < CHUNK_D; z++) {
|
||||||
}
|
for (uint x = 0; x < CHUNK_W; x++) {
|
||||||
auto& otherPrototype = requirePrototype(
|
float rand = (structsRand.randU32() % RAND_MAX) /
|
||||||
chunkX + lcx, chunkZ + lcz
|
static_cast<float>(RAND_MAX);
|
||||||
);
|
const Biome* biome = biomes[z * CHUNK_W + x];
|
||||||
auto chunkAABB = gen_chunk_aabb(chunkX + lcx, chunkZ + lcz);
|
size_t structureId = biome->structures.choose(rand, -1);
|
||||||
if (chunkAABB.intersect(aabb)) {
|
if (structureId == -1) {
|
||||||
otherPrototype.structures.emplace_back(
|
continue;
|
||||||
placement.structure,
|
|
||||||
placement.position -
|
|
||||||
glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D),
|
|
||||||
placement.rotation
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
uint8_t rotation = structsRand.randU32() % 4;
|
||||||
|
int height = heights[z * CHUNK_W + x] * CHUNK_H;
|
||||||
|
if (height < def.script->getSeaLevel()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto& structure = *def.structures[structureId]->fragments[rotation];
|
||||||
|
glm::ivec3 position {x, height, z};
|
||||||
|
position.x -= structure.getSize().x / 2;
|
||||||
|
position.z -= structure.getSize().z / 2;
|
||||||
|
prototype.structures.push_back({
|
||||||
|
static_cast<int>(structureId), position, rotation});
|
||||||
|
placeStructure(
|
||||||
|
position,
|
||||||
|
structureId,
|
||||||
|
rotation,
|
||||||
|
chunkX,
|
||||||
|
chunkZ
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prototype.level = ChunkPrototypeLevel::STRUCTURES;
|
prototype.level = ChunkPrototypeLevel::STRUCTURES;
|
||||||
@ -260,14 +302,12 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: put automatic placement here
|
|
||||||
|
|
||||||
for (const auto& placement : prototype.structures) {
|
for (const auto& placement : prototype.structures) {
|
||||||
if (placement.structure < 0 || placement.structure >= structures.size()) {
|
if (placement.structure < 0 || placement.structure >= def.structures.size()) {
|
||||||
logger.error() << "invalid structure index " << placement.structure;
|
logger.error() << "invalid structure index " << placement.structure;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto& structure = *structures[placement.structure][placement.rotation];
|
auto& structure = *def.structures[placement.structure]->fragments[placement.rotation];
|
||||||
auto& structVoxels = structure.getRuntimeVoxels();
|
auto& structVoxels = structure.getRuntimeVoxels();
|
||||||
const auto& offset = placement.position;
|
const auto& offset = placement.position;
|
||||||
const auto& size = structure.getSize();
|
const auto& size = structure.getSize();
|
||||||
|
|||||||
@ -47,8 +47,6 @@ class WorldGenerator {
|
|||||||
/// @brief Chunk prototypes loading surround map
|
/// @brief Chunk prototypes loading surround map
|
||||||
SurroundMap surroundMap;
|
SurroundMap surroundMap;
|
||||||
|
|
||||||
std::vector<std::array<std::shared_ptr<VoxelFragment>, 4>> structures;
|
|
||||||
|
|
||||||
/// @brief Generate chunk prototype (see ChunkPrototype)
|
/// @brief Generate chunk prototype (see ChunkPrototype)
|
||||||
/// @param x chunk position X divided by CHUNK_W
|
/// @param x chunk position X divided by CHUNK_W
|
||||||
/// @param z chunk position Y divided by CHUNK_D
|
/// @param z chunk position Y divided by CHUNK_D
|
||||||
@ -61,6 +59,11 @@ class WorldGenerator {
|
|||||||
void generateBiomes(ChunkPrototype& prototype, int x, int z);
|
void generateBiomes(ChunkPrototype& prototype, int x, int z);
|
||||||
|
|
||||||
void generateHeightmap(ChunkPrototype& prototype, int x, int z);
|
void generateHeightmap(ChunkPrototype& prototype, int x, int z);
|
||||||
|
|
||||||
|
void placeStructure(
|
||||||
|
const glm::ivec3 offset, size_t structure, uint8_t rotation,
|
||||||
|
int chunkX, int chunkZ
|
||||||
|
);
|
||||||
public:
|
public:
|
||||||
WorldGenerator(
|
WorldGenerator(
|
||||||
const GeneratorDef& def,
|
const GeneratorDef& def,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user