feat: add deriveSeed
This commit is contained in:
1 parent
db3b841aec
commit
62ae595999
1 file changed
+152
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user