add :block placement for single blocks

This commit is contained in:
eliotbyte 2025-10-24 15:51:20 +03:00 committed by MihailRis
parent 2af7b23b2e
commit 9ccaecddd2
4 changed files with 153 additions and 7 deletions

View File

@ -152,6 +152,32 @@ public:
placements.emplace_back(priority, LinePlacement {block, a, b, radius});
}
void perform_block(lua::State* L, std::vector<Placement>& placements) {
rawgeti(L, 2);
blockid_t block = touinteger(L, -1);
pop(L);
rawgeti(L, 3);
glm::ivec3 pos = tovec3(L, -1);
pop(L);
uint8_t rotation = 0;
if (objlen(L, -1) >= 4) {
rawgeti(L, 4);
rotation = tointeger(L, -1) & 0b11;
pop(L);
}
int priority = 0;
if (objlen(L, -1) >= 5) {
rawgeti(L, 5);
priority = tointeger(L, -1);
pop(L);
}
placements.emplace_back(priority, BlockPlacement {block, pos, rotation});
}
void perform_placement(lua::State* L, std::vector<Placement>& placements) {
rawgeti(L, 1);
int structIndex = 0;
@ -162,6 +188,11 @@ public:
perform_line(L, placements);
return;
} else if (!std::strcmp(name, ":block")) {
pop(L);
perform_block(L, placements);
return;
}
const auto& found = def.structuresIndices.find(name);
if (found != def.structuresIndices.end()) {

View File

@ -27,12 +27,22 @@ struct LinePlacement {
}
};
struct BlockPlacement {
blockid_t block;
glm::ivec3 position;
uint8_t rotation;
BlockPlacement(blockid_t block, glm::ivec3 position, uint8_t rotation)
: block(block), position(std::move(position)), rotation(rotation) {
}
};
struct Placement {
int priority;
std::variant<StructurePlacement, LinePlacement> placement;
std::variant<StructurePlacement, LinePlacement, BlockPlacement> placement;
Placement(
int priority,
std::variant<StructurePlacement, LinePlacement> placement
std::variant<StructurePlacement, LinePlacement, BlockPlacement> placement
) : priority(priority), placement(std::move(placement)) {}
};

View File

@ -204,6 +204,46 @@ void WorldGenerator::placeLine(const LinePlacement& line, int priority) {
}
}
void WorldGenerator::placeBlock(const BlockPlacement& block, int priority) {
// Compute world-space AABB of the extended block to distribute to prototypes
const auto& indices = content.getIndices()->blocks;
const auto& def = indices.require(block.block);
const auto& rot = def.rotations.variants[block.rotation & 0b11];
glm::ivec3 minp = block.position;
glm::ivec3 maxp = block.position;
const auto size = def.size;
for (int sy = 0; sy < size.y; sy++) {
for (int sz = 0; sz < size.z; sz++) {
for (int sx = 0; sx < size.x; sx++) {
glm::ivec3 p = block.position;
p += rot.axes[0] * sx;
p += rot.axes[1] * sy;
p += rot.axes[2] * sz;
minp = glm::min(minp, p);
maxp = glm::max(maxp, p);
}
}
}
// inclusive-exclusive for max; expand by 1 to compute chunk coverage
maxp += glm::ivec3(1, 1, 1);
AABB aabb(minp, maxp);
int cxa = floordiv<CHUNK_W>(aabb.a.x);
int cza = floordiv<CHUNK_D>(aabb.a.z);
int cxb = floordiv<CHUNK_W>(aabb.b.x);
int czb = floordiv<CHUNK_D>(aabb.b.z);
for (int cz = cza; cz <= czb; cz++) {
for (int cx = cxa; cx <= cxb; cx++) {
const auto& found = prototypes.find({cx, cz});
if (found != prototypes.end()) {
// position becomes relative to prototype chunk
glm::ivec3 rel = block.position - glm::ivec3(cx * CHUNK_W, 0, cz * CHUNK_D);
found->second->placements.emplace_back(priority, BlockPlacement{block.block, rel, block.rotation});
}
}
}
}
void WorldGenerator::placeStructures(
const std::vector<Placement>& placements,
ChunkPrototype& prototype,
@ -217,9 +257,11 @@ void WorldGenerator::placeStructures(
continue;
}
placeStructure(*sp, placement.priority, chunkX, chunkZ);
} else if (auto lp = std::get_if<LinePlacement>(&placement.placement)) {
placeLine(*lp, placement.priority);
} else {
const auto& line = std::get<LinePlacement>(placement.placement);
placeLine(line, placement.priority);
const auto& bp = std::get<BlockPlacement>(placement.placement);
placeBlock(bp, placement.priority);
}
}
}
@ -482,9 +524,10 @@ void WorldGenerator::generatePlacements(
for (const auto& placement : placements) {
if (auto structure = std::get_if<StructurePlacement>(&placement.placement)) {
generateStructure(prototype, *structure, voxels, chunkX, chunkZ);
} else {
const auto& line = std::get<LinePlacement>(placement.placement);
generateLine(prototype, line, voxels, chunkX, chunkZ);
} else if (auto line = std::get_if<LinePlacement>(&placement.placement)) {
generateLine(prototype, *line, voxels, chunkX, chunkZ);
} else if (auto block = std::get_if<BlockPlacement>(&placement.placement)) {
generateBlock(prototype, *block, voxels, chunkX, chunkZ);
}
}
}
@ -591,6 +634,61 @@ void WorldGenerator::generateLine(
}
}
void WorldGenerator::generateBlock(
const ChunkPrototype& prototype,
const BlockPlacement& placement,
voxel* voxels,
int chunkX, int chunkZ
) {
const auto& indices = content.getIndices()->blocks;
const auto& def = indices.require(placement.block);
int cgx = chunkX * CHUNK_W;
int cgz = chunkZ * CHUNK_D;
glm::ivec3 origin = placement.position; // already relative to chunk in placeBlock
if (origin.x < 0 || origin.x >= CHUNK_W ||
origin.z < 0 || origin.z >= CHUNK_D ||
origin.y < 0 || origin.y >= CHUNK_H) {
return;
}
// write origin voxel
auto& vox = voxels[vox_index(origin.x, origin.y, origin.z)];
vox.id = placement.block;
vox.state = {};
vox.state.rotation = placement.rotation & 0b11;
// expand extended blocks
if (def.rt.extended) {
const auto& rot = def.rotations.variants[vox.state.rotation];
const auto size = def.size;
for (int sy = 0; sy < size.y; sy++) {
for (int sz = 0; sz < size.z; sz++) {
for (int sx = 0; sx < size.x; sx++) {
if ((sx | sy | sz) == 0) continue;
glm::ivec3 pos = origin;
pos += rot.axes[0] * sx;
pos += rot.axes[1] * sy;
pos += rot.axes[2] * sz;
if (pos.x < 0 || pos.x >= CHUNK_W ||
pos.y < 0 || pos.y >= CHUNK_H ||
pos.z < 0 || pos.z >= CHUNK_D) {
continue;
}
struct voxel seg;
seg.id = placement.block;
seg.state = {};
seg.state.rotation = vox.state.rotation;
seg.state.segment = ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2));
voxels[vox_index(pos.x, pos.y, pos.z)] = seg;
}
}
}
}
}
WorldGenDebugInfo WorldGenerator::createDebugInfo() const {
const auto& area = surroundMap.getArea();
const auto& levels = area.getBuffer();

View File

@ -79,6 +79,7 @@ class WorldGenerator {
);
void placeLine(const LinePlacement& line, int priority);
void placeBlock(const BlockPlacement& block, int priority);
void generatePlacements(
const ChunkPrototype& prototype, voxel* voxels, int x, int z
@ -89,6 +90,12 @@ class WorldGenerator {
voxel* voxels,
int x, int z
);
void generateBlock(
const ChunkPrototype& prototype,
const BlockPlacement& placement,
voxel* voxels,
int x, int z
);
void generateStructure(
const ChunkPrototype& prototype,
const StructurePlacement& placement,