fix caves issues & add block 'surface-replacement' property

This commit is contained in:
MihailRis 2024-10-08 22:37:41 +03:00
parent c022e11c3b
commit b4578cfb87
7 changed files with 115 additions and 18 deletions

View File

@ -1,4 +1,5 @@
{
"texture": "dirt",
"material": "base:ground"
}
"material": "base:ground",
"surface-replacement": "base:grass_block"
}

View File

@ -82,6 +82,7 @@ std::unique_ptr<Content> ContentBuilder::build() {
// Now, it's time to resolve foreign keys
for (Block* def : blockDefsIndices) {
def->rt.pickingItem = content->items.require(def->pickingItem).rt.id;
def->rt.surfaceReplacement = content->blocks.require(def->surfaceReplacement).rt.id;
}
for (ItemDef* def : itemDefsIndices) {

View File

@ -286,6 +286,7 @@ void ContentLoader::loadBlock(
root.at("hidden").get(def.hidden);
root.at("draw-group").get(def.drawGroup);
root.at("picking-item").get(def.pickingItem);
root.at("surface-replacement").get(def.surfaceReplacement);
root.at("script-name").get(def.scriptName);
root.at("ui-layout").get(def.uiLayout);
root.at("inventory-size").get(def.inventorySize);

View File

@ -74,8 +74,8 @@ namespace util {
/// @note glm::distance2 does not support integer vectors
inline int distance2(const glm::ivec3& a, const glm::ivec3& b) {
return (b.x - a.x) * (b.x - a.x) +
(b.y - a.y) * (b.y - a.y) +
(b.z - a.z) * (b.z - a.z);
(b.y - a.y) * (b.y - a.y) +
(b.z - a.z) * (b.z - a.z);
}
/// @return integer square of distance between two points

View File

@ -181,6 +181,9 @@ public:
/// @brief Block script name in blocks/ without extension
std::string scriptName = name.substr(name.find(':') + 1);
/// @brief Block will be used instead of this if generated on surface
std::string surfaceReplacement = name;
/// @brief Default block layout will be used by hud.open_block(...)
std::string uiLayout = name;
@ -214,6 +217,8 @@ public:
/// @brief picking item integer id
itemid_t pickingItem = 0;
blockid_t surfaceReplacement = 0;
} rt {};
Block(const std::string& name);

View File

@ -305,6 +305,65 @@ void WorldGenerator::update(int centerX, int centerY, int loadDistance) {
surroundMap.setCenter(centerX, centerY);
}
void WorldGenerator::generatePlants(
const ChunkPrototype& prototype,
float* heights,
voxel* voxels,
int chunkX,
int chunkZ,
const Biome** biomes
) {
const auto& indices = content->getIndices()->blocks;
util::PseudoRandom plantsRand;
plantsRand.setSeed(chunkX, chunkZ);
for (uint z = 0; z < CHUNK_D; z++) {
for (uint x = 0; x < CHUNK_W; x++) {
const Biome* biome = biomes[z * CHUNK_W + x];
int height = heights[z * CHUNK_W + x] * CHUNK_H;
height = std::max(0, height);
if (height+1 > def.seaLevel) {
float rand = plantsRand.randFloat();
blockid_t plant = biome->plants.choose(rand);
if (plant) {
auto& voxel = voxels[vox_index(x, height+1, z)];
auto& groundVoxel = voxels[vox_index(x, height, z)];
if (indices.get(groundVoxel.id)->rt.solid) {
voxel = {plant, {}};
}
}
}
}
}
}
void WorldGenerator::generateLand(
const ChunkPrototype& prototype,
float* values,
voxel* voxels,
int chunkX,
int chunkZ,
const Biome** biomes
) {
uint seaLevel = def.seaLevel;
for (uint z = 0; z < CHUNK_D; z++) {
for (uint x = 0; x < CHUNK_W; x++) {
const Biome* biome = biomes[z * CHUNK_W + x];
int height = values[z * CHUNK_W + x] * CHUNK_H;
height = std::max(0, height);
const auto& groundLayers = biome->groundLayers;
const auto& seaLayers = biome->seaLayers;
generate_pole(seaLayers, seaLevel, height, seaLevel, voxels, x, z);
generate_pole(groundLayers, height, 0, seaLevel, voxels, x, z);
}
}
}
void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
surroundMap.completeAt(chunkX, chunkZ);
@ -315,9 +374,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
std::memset(voxels, 0, sizeof(voxel) * CHUNK_VOL);
util::PseudoRandom plantsRand;
plantsRand.setSeed(chunkX, chunkZ);
const auto& indices = content->getIndices()->blocks;
const auto& biomes = prototype.biomes.get();
for (uint z = 0; z < CHUNK_D; z++) {
for (uint x = 0; x < CHUNK_W; x++) {
@ -331,18 +388,20 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) {
generate_pole(seaLayers, seaLevel, height, seaLevel, voxels, x, z);
generate_pole(groundLayers, height, 0, seaLevel, voxels, x, z);
if (height+1 > seaLevel) {
float rand = plantsRand.randFloat();
blockid_t plant = biome->plants.choose(rand);
if (plant) {
voxels[vox_index(x, height+1, z)].id = plant;
}
}
}
}
generateLines(prototype, voxels, chunkX, chunkZ);
generatePlants(prototype, values, voxels, chunkX, chunkZ, biomes);
generateStructures(prototype, voxels, chunkX, chunkZ);
#ifndef NDEBUG
for (uint i = 0; i < CHUNK_VOL; i++) {
blockid_t id = voxels[i].id;
if (indices.get(id) == nullptr) {
abort();
}
}
#endif
}
void WorldGenerator::generateStructures(
@ -391,11 +450,12 @@ void WorldGenerator::generateStructures(
void WorldGenerator::generateLines(
const ChunkPrototype& prototype, voxel* voxels, int chunkX, int chunkZ
) {
const auto& indices = content->getIndices()->blocks;
for (const auto& line : prototype.lines) {
int cgx = chunkX * CHUNK_W;
int cgz = chunkZ * CHUNK_D;
int radius = line.radius;
int const radius = line.radius;
auto a = line.a;
auto b = line.b;
@ -418,8 +478,21 @@ void WorldGenerator::generateLines(
glm::ivec3 closest = util::closest_point_on_segment(
a, b, point
);
if (util::distance2(closest, point) <= radius*radius) {
voxels[vox_index(x, y, z)] = {line.block, {}};
if (y > 0 && util::distance2(closest, point) <= radius*radius && line.block == BLOCK_AIR) {
auto& voxel = voxels[vox_index(x, y, z)];
if (!indices.require(voxel.id).replaceable) {
voxel = {line.block, {}};
}
auto& below = voxels[vox_index(x, y-1, z)];
glm::ivec3 closest2 = util::closest_point_on_segment(
a, b, {gx, y-1, gz}
);
if (util::distance2(closest2, {gx, y-1, gz}) > radius*radius) {
const auto& def = indices.require(below.id);
if (def.rt.surfaceReplacement != below.id) {
below = {def.rt.surfaceReplacement, {}};
}
}
}
}
}

View File

@ -83,6 +83,22 @@ class WorldGenerator {
void generateStructures(
const ChunkPrototype& prototype, voxel* voxels, int x, int z
);
void generatePlants(
const ChunkPrototype& prototype,
float* values,
voxel* voxels,
int x,
int z,
const Biome** biomes
);
void generateLand(
const ChunkPrototype& prototype,
float* values,
voxel* voxels,
int x,
int z,
const Biome** biomes
);
public:
WorldGenerator(
const GeneratorDef& def,