Collect biome data

We store the biome data as grayscale images, as biome indices are
represented as bytes and we get PNG compression for free.
This commit is contained in:
Matthias Schiffer 2020-06-19 20:34:42 +02:00
parent dc97c4a8c1
commit f539d668eb
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
3 changed files with 81 additions and 23 deletions

View file

@ -52,6 +52,20 @@ namespace MinedMap {
static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE; static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE;
static void addChunkBiome(uint8_t biomemap[DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) {
World::Chunk chunk(data);
World::Chunk::Blocks layer = chunk.getTopLayer();
for (size_t x = 0; x < World::Chunk::SIZE; x++) {
for (size_t z = 0; z < World::Chunk::SIZE; z++) {
size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x;
const World::Block &block = layer.blocks[x][z];
biomemap[i] = chunk.getBiome(x, block.height, z);
}
}
}
static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) { static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) {
World::Chunk chunk(data); World::Chunk chunk(data);
World::Chunk::Blocks layer = chunk.getTopLayer(); World::Chunk::Blocks layer = chunk.getTopLayer();
@ -105,35 +119,56 @@ static void writeImage(const std::string &output, const uint8_t *data, PNG::Form
} }
} }
static void doRegion(const std::string &input, const std::string &output, const std::string &output_light) { static int64_t checkRegion(const std::string &input, const std::string &output) {
int64_t intime; struct stat s;
{ if (stat(input.c_str(), &s) < 0) {
struct stat instat; if (errno != ENOENT)
std::fprintf(stderr, "Unable to stat %s: %s\n", input.c_str(), std::strerror(errno));
if (stat(input.c_str(), &instat) < 0) { return INT64_MIN;
if (errno != ENOENT) }
std::fprintf(stderr, "Unable to stat %s: %s\n", input.c_str(), std::strerror(errno));
return;
}
#ifdef _WIN32 #ifdef _WIN32
intime = (int64_t)instat.st_mtime * 1000000; int64_t intime = (int64_t)s.st_mtime * 1000000;
#else #else
intime = (int64_t)instat.st_mtim.tv_sec * 1000000 + instat.st_mtim.tv_nsec / 1000; int64_t intime = (int64_t)s.st_mtim.tv_sec * 1000000 + s.st_mtim.tv_nsec / 1000;
#endif #endif
if (stat(output.c_str(), &s) < 0)
return intime;
int64_t outtime = readStamp(output);
if (intime <= outtime) {
std::printf("%s is up-to-date.\n", output.c_str());
return INT64_MIN;
} }
{ return intime;
struct stat s; }
if (stat(output.c_str(), &s) == 0) {
int64_t outtime = readStamp(output); static void doRegionBiome(const std::string &input, const std::string &output) {
if (intime <= outtime) { int64_t intime = checkRegion(input, output);
std::printf("%s is up-to-date.\n", output.c_str()); if (intime == INT64_MIN)
return; return;
}
} std::printf("Generating %s from %s...\n", output.c_str(), input.c_str());
try {
std::unique_ptr<uint8_t[]> biomemap(new uint8_t[DIM*DIM]);
std::memset(biomemap.get(), 0, DIM*DIM);
World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) { addChunkBiome(biomemap.get(), X, Z, chunk); });
writeImage(output, biomemap.get(), PNG::GRAY, intime);
} catch (const std::exception& ex) {
std::fprintf(stderr, "Failed to generate %s: %s\n", output.c_str(), ex.what());
} }
}
static void doRegion(const std::string &input, const std::string &output, const std::string &output_light) {
int64_t intime = checkRegion(input, output);
if (intime == INT64_MIN)
return;
std::printf("Generating %s from %s...\n", output.c_str(), input.c_str()); std::printf("Generating %s from %s...\n", output.c_str(), input.c_str());
@ -187,6 +222,22 @@ static void makeDir(const std::string &name) {
throw std::system_error(errno, std::generic_category(), "unable to create directory " + name); throw std::system_error(errno, std::generic_category(), "unable to create directory " + name);
} }
static void makeBiome(const std::string &regiondir, const std::string &outputdir, size_t x, size_t z) {
std::string inname = formatTileName(x, z, "mca");
std::string outname = formatTileName(x, z, "png");
doRegionBiome(regiondir + "/" + inname, outputdir + "/biome/" + outname);
}
static void makeBiomes(const std::string &regiondir, const std::string &outputdir, const Info *info) {
int minX, maxX, minZ, maxZ;
std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0);
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++)
makeBiome(regiondir, outputdir, x, z);
}
}
static void makeMap(const std::string &regiondir, const std::string &outputdir, size_t x, size_t z) { static void makeMap(const std::string &regiondir, const std::string &outputdir, size_t x, size_t z) {
std::string inname = formatTileName(x, z, "mca"); std::string inname = formatTileName(x, z, "mca");
std::string outname = formatTileName(x, z, "png"); std::string outname = formatTileName(x, z, "png");
@ -321,6 +372,7 @@ static Info collectInfo(const std::string &regiondir) {
static void doLevel(const std::string &inputdir, const std::string &outputdir) { static void doLevel(const std::string &inputdir, const std::string &outputdir) {
const std::string regiondir = inputdir + "/region"; const std::string regiondir = inputdir + "/region";
makeDir(outputdir + "/biome");
makeDir(outputdir + "/map"); makeDir(outputdir + "/map");
makeDir(outputdir + "/map/0"); makeDir(outputdir + "/map/0");
makeDir(outputdir + "/light"); makeDir(outputdir + "/light");
@ -328,6 +380,9 @@ static void doLevel(const std::string &inputdir, const std::string &outputdir) {
Info info = collectInfo(regiondir); Info info = collectInfo(regiondir);
std::printf("Updating biome data...\n");
makeBiomes(regiondir, outputdir, &info);
std::printf("Updating map data...\n"); std::printf("Updating map data...\n");
makeMaps(regiondir, outputdir, &info); makeMaps(regiondir, outputdir, &info);

View file

@ -75,8 +75,10 @@ uint8_t Chunk::getBiome(size_t x, size_t y, size_t z) const {
return biomeInts->getValue((y/BGROUP)*BSIZE*BSIZE + (z/BGROUP)*BSIZE + (x/BGROUP)); return biomeInts->getValue((y/BGROUP)*BSIZE*BSIZE + (z/BGROUP)*BSIZE + (x/BGROUP));
else if (biomeIntsPre115) else if (biomeIntsPre115)
return biomeIntsPre115->getValue(z*SIZE + x); return biomeIntsPre115->getValue(z*SIZE + x);
else else if (biomeBytes)
return biomeBytes->getValue(z*SIZE + x); return biomeBytes->getValue(z*SIZE + x);
else
return 0;
} }
bool Chunk::getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const { bool Chunk::getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const {

View file

@ -62,7 +62,6 @@ private:
std::shared_ptr<const NBT::IntArrayTag> biomeIntsPre115; std::shared_ptr<const NBT::IntArrayTag> biomeIntsPre115;
std::shared_ptr<const NBT::IntArrayTag> biomeInts; std::shared_ptr<const NBT::IntArrayTag> biomeInts;
uint8_t getBiome(size_t x, size_t y, size_t z) const;
bool getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const; bool getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const;
public: public:
@ -72,6 +71,8 @@ public:
return *level; return *level;
} }
uint8_t getBiome(size_t x, size_t y, size_t z) const;
const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const { const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const {
size_t Y = y / SIZE; size_t Y = y / SIZE;