Files

99 lines
3.4 KiB
C++

#pragma once
#include <cstdint>
#include <vector>
#include "World.h"
namespace vf {
enum class StructureGenKind : uint8_t {
Village = 0,
Dungeon = 1,
Mineshaft = 2,
Ravine = 3,
DesertTemple = 4,
Count,
};
struct BoundingBoxI {
Vec3i min;
Vec3i max;
bool contains(const Vec3i& p) const {
return p.x >= min.x && p.x <= max.x &&
p.y >= min.y && p.y <= max.y &&
p.z >= min.z && p.z <= max.z;
}
bool intersects(const BoundingBoxI& other) const {
return min.x <= other.max.x && max.x >= other.min.x &&
min.y <= other.max.y && max.y >= other.min.y &&
min.z <= other.max.z && max.z >= other.min.z;
}
};
struct StructurePiece {
Vec3i offset; // relative to StructurePlan::origin
Block block;
};
struct StructurePlan {
StructureGenKind kind = StructureGenKind::Village;
Vec3i origin; // world-space anchor
BoundingBoxI bounds; // world-space, covers every piece
std::vector<StructurePiece> pieces;
};
struct StructureGenParams {
uint32_t seed = 1337u;
int chunkSize = 16;
int villageChance = 42; // 1 in N chunks host a village
int dungeonChance = 37;
int mineshaftChance = 53;
int ravineChance = 61;
int templeChance = 71;
};
// Deterministic 32-bit mix of seed, chunk coordinate and a salt distinguishing
// use sites. Named apart from vf::structureHash in Structures.h to avoid a
// duplicate symbol when both translation units link together.
uint32_t chunkStructureHash(uint32_t seed, int chunkX, int chunkZ, uint32_t salt);
// Deterministic per-chunk structure placement and piece-list generation:
// village (house grid + paths), dungeon (room + spawner + chests), mineshaft
// (branching corridors + supports), ravine (carved canyon) and desert temple
// (stepped pyramid + hidden chamber). Every method is a pure function of its
// inputs, so identical seed and chunk coordinates always produce an
// identical plan.
class StructureGen {
public:
explicit StructureGen(const StructureGenParams& params = {});
// Decides whether chunk (chunkX, chunkZ) hosts a structure and which
// kind, in priority order village > temple > dungeon > mineshaft > ravine.
bool structureForChunk(int chunkX, int chunkZ, StructureGenKind& outKind) const;
// Builds the full piece list and bounding box for `kind` anchored at
// groundY within chunk (chunkX, chunkZ).
StructurePlan buildStructure(StructureGenKind kind, int chunkX, int chunkZ, int groundY) const;
// Writes every piece into the world, skipping pieces that fall outside
// [0, maxY).
void stamp(World& world, const StructurePlan& plan, int maxY) const;
const StructureGenParams& settings() const { return params; }
private:
StructurePlan buildVillage(int chunkX, int chunkZ, int groundY, uint32_t rngState) const;
StructurePlan buildDungeon(int chunkX, int chunkZ, int groundY, uint32_t rngState) const;
StructurePlan buildMineshaft(int chunkX, int chunkZ, int groundY, uint32_t rngState) const;
StructurePlan buildRavine(int chunkX, int chunkZ, int groundY, uint32_t rngState) const;
StructurePlan buildTemple(int chunkX, int chunkZ, int groundY, uint32_t rngState) const;
BoundingBoxI computeBounds(const Vec3i& origin, const std::vector<StructurePiece>& pieces) const;
StructureGenParams params;
};
} // namespace vf