feat: add deriveSeed

This commit is contained in:
dualfroz committed 2026-09-07 14:22:09 +02:00
1 parent db3b841aec
commit 62ae595999
1 file changed
+152
+152
View File
@@ -0,0 +1,152 @@
#include "vf/Dimension.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
namespace vf {
namespace {
constexpr long long ticksPerDay = 24000;
// A destination portal site is only worth taking if it sits within this many
// blocks of the scaled arrival height; otherwise a platform is cheaper than a
// long fall or a climb to the roof.
constexpr int safeSpotVerticalBand = 32;
uint32_t deriveSeed(uint32_t baseSeed, uint32_t salt) {
uint64_t h = baseSeed;
h ^= salt + 0x9E3779B97F4A7C15ull + (h << 6) + (h >> 2);
h *= 1099511628211ull;
return static_cast<uint32_t>(h ^ (h >> 32));
}
} // namespace
DimensionConfig DimensionConfig::forDimension(DimensionId id) {
DimensionConfig cfg;
cfg.id = id;
switch (id) {
case DimensionId::Nether:
cfg.floorY = 0;
cfg.ceilingY = 128;
cfg.hasSky = false;
cfg.hasCeiling = true;
cfg.hasDayCycle = false;
cfg.waterEvaporates = true;
cfg.bedsExplode = true;
cfg.coordinateScale = 8.0f;
cfg.ambientLight = 0.10f;
cfg.seedSalt = 0x4e544852u;
break;
case DimensionId::End:
cfg.floorY = 0;
cfg.ceilingY = 128;
cfg.hasSky = false;
cfg.hasCeiling = false;
cfg.hasDayCycle = false;
cfg.waterEvaporates = false;
cfg.bedsExplode = true;
cfg.coordinateScale = 1.0f;
cfg.ambientLight = 0.04f;
cfg.seedSalt = 0x454e4421u;
break;
default:
cfg.floorY = 0;
cfg.ceilingY = 128;
cfg.hasSky = true;
cfg.hasCeiling = false;
cfg.hasDayCycle = true;
cfg.waterEvaporates = false;
cfg.bedsExplode = false;
cfg.coordinateScale = 1.0f;
cfg.ambientLight = 0.0f;
cfg.seedSalt = 0u;
break;
}
return cfg;
}
const char* DimensionConfig::nameOf(DimensionId id) {
switch (id) {
case DimensionId::Nether: return "nether";
case DimensionId::End: return "end";
default: return "overworld";
}
}
int DimensionConfig::clampY(int y) const {
int low = lowestPlaceableY();
int high = highestPlaceableY();
if (y < low) return low;
if (y > high) return high;
return y;
}
Dimension::Dimension(const DimensionConfig& dimensionConfig, uint32_t worldSeed)
: cfg(dimensionConfig), derivedSeed(deriveSeed(worldSeed, dimensionConfig.seedSalt)) {
switch (cfg.id) {
case DimensionId::Nether: {
NetherGenerator::Params netherParams;
netherParams.seed = derivedSeed;
netherParams.floorY = cfg.floorY;
netherParams.ceilingY = cfg.ceilingY;
nether = std::make_unique<NetherGenerator>(netherParams);
break;
}
case DimensionId::End: {
EndGenerator::Params endParams;
endParams.seed = derivedSeed;
endParams.floorY = cfg.floorY;
endParams.ceilingY = cfg.ceilingY;
end = std::make_unique<EndGenerator>(endParams);
break;
}
default: {
WorldGenParams overworldParams;
overworldParams.seed = derivedSeed;
overworldParams.maxY = cfg.ceilingY;
overworld = std::make_unique<WorldGen>(overworldParams);
break;
}
}
}
bool Dimension::columnGenerated(int columnX, int columnZ) const {
return columns.find(Vec3i{columnX, 0, columnZ}) != columns.end();
}
void Dimension::generateColumn(int columnX, int columnZ) {
if (!columns.insert(Vec3i{columnX, 0, columnZ}).second) return;
if (nether) nether->generateColumn(blocks, columnX, columnZ);
else if (end) end->generateColumn(blocks, columnX, columnZ);
else overworld->generateColumn(blocks, columnX, columnZ);
}
int Dimension::generateArea(int columnX, int columnZ, int columnRadius) {
int made = 0;
for (int dx = -columnRadius; dx <= columnRadius; ++dx) {
for (int dz = -columnRadius; dz <= columnRadius; ++dz) {
if (columnGenerated(columnX + dx, columnZ + dz)) continue;
generateColumn(columnX + dx, columnZ + dz);
++made;
}
}
return made;
}
float Dimension::dayFraction() const {
if (!cfg.hasDayCycle) return 0.0f;
long long phase = elapsed % ticksPerDay;
if (phase < 0) phase += ticksPerDay;
return static_cast<float>(phase) / static_cast<float>(ticksPerDay);
}
int Dimension::highestSolidY(int gx, int gz) const {
for (int y = cfg.ceilingY - 1; y >= cfg.floorY; --y)
if (blocks.solidAt(gx, y, gz)) return y;
return cfg.floorY - 1;
}