From b26f3134692d32534eb53198a373b7ccc29effdb Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 23 Aug 2026 19:48:19 +0200 Subject: [PATCH] feat(core): declare structure placement across generated terrain interface --- core/include/vf/StructureGen.h | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 core/include/vf/StructureGen.h diff --git a/core/include/vf/StructureGen.h b/core/include/vf/StructureGen.h new file mode 100644 index 0000000..6ee6520 --- /dev/null +++ b/core/include/vf/StructureGen.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#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 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& pieces) const; + + StructureGenParams params; +}; + +} // namespace vf