mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-04 17:23:33 +01:00
Introduce separate types for block/section/chunk indices
Newtypes are cumbersome in C++, so this is mostly documentation for now. Also replace lots of questionable uses of size_t with int or types with explicit width and add a few comments for constants.
This commit is contained in:
parent
d4be401bcd
commit
457e993c92
13 changed files with 123 additions and 92 deletions
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2015-2019, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -32,15 +32,15 @@
|
||||||
namespace MinedMap {
|
namespace MinedMap {
|
||||||
|
|
||||||
static const int BIOME_SMOOTH = 3;
|
static const int BIOME_SMOOTH = 3;
|
||||||
static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE;
|
static const uint32_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) {
|
static void addChunkBiome(uint8_t biomemap[DIM*DIM], chunk_idx_t X, chunk_idx_t Z, const World::ChunkData *data) {
|
||||||
World::Chunk chunk(data);
|
World::Chunk chunk(data);
|
||||||
World::Chunk::Heightmap layer = chunk.getTopLayer(0);
|
World::Chunk::Heightmap layer = chunk.getTopLayer(0);
|
||||||
|
|
||||||
for (size_t x = 0; x < World::Chunk::SIZE; x++) {
|
for (block_idx_t x = 0; x < World::Chunk::SIZE; x++) {
|
||||||
for (size_t z = 0; z < World::Chunk::SIZE; z++) {
|
for (block_idx_t z = 0; z < World::Chunk::SIZE; z++) {
|
||||||
size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x;
|
size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x;
|
||||||
const World::Chunk::Height &height = layer.v[x][z];
|
const World::Chunk::Height &height = layer.v[x][z];
|
||||||
biomemap[i] = chunk.getBiome(x, height.y, z);
|
biomemap[i] = chunk.getBiome(x, height.y, z);
|
||||||
|
@ -48,20 +48,20 @@ static void addChunkBiome(uint8_t biomemap[DIM*DIM], size_t X, size_t Z, const W
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t biomeAt(ssize_t x, ssize_t z, const std::unique_ptr<uint8_t[]> biomemaps[3][3]) {
|
static uint8_t biomeAt(int16_t x, int16_t z, const std::unique_ptr<uint8_t[]> biomemaps[3][3]) {
|
||||||
size_t a = 1, b = 1;
|
size_t a = 1, b = 1;
|
||||||
|
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
a--;
|
a--;
|
||||||
x += DIM;
|
x += DIM;
|
||||||
} else if (x >= (ssize_t)DIM) {
|
} else if (x >= (int32_t)DIM) {
|
||||||
a++;
|
a++;
|
||||||
x -= DIM;
|
x -= DIM;
|
||||||
}
|
}
|
||||||
if (z < 0) {
|
if (z < 0) {
|
||||||
b--;
|
b--;
|
||||||
z += DIM;
|
z += DIM;
|
||||||
} else if (z >= (ssize_t)DIM) {
|
} else if (z >= (int32_t)DIM) {
|
||||||
b++;
|
b++;
|
||||||
z -= DIM;
|
z -= DIM;
|
||||||
}
|
}
|
||||||
|
@ -69,10 +69,13 @@ static uint8_t biomeAt(ssize_t x, ssize_t z, const std::unique_ptr<uint8_t[]> bi
|
||||||
return biomemaps[a][b].get()[z*DIM + x];
|
return biomemaps[a][b].get()[z*DIM + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Resource::Color collectColors(size_t x, size_t z, const World::Block &block, const std::unique_ptr<uint8_t[]> biomemaps[3][3]) {
|
static Resource::Color collectColors(
|
||||||
std::unordered_map<uint8_t, size_t> biomes;
|
region_block_idx_t x, region_block_idx_t z,
|
||||||
for (int dx = -BIOME_SMOOTH; dx <= BIOME_SMOOTH; dx++) {
|
const World::Block &block, const std::unique_ptr<uint8_t[]> biomemaps[3][3]
|
||||||
for (int dz = -BIOME_SMOOTH; dz <= BIOME_SMOOTH; dz++) {
|
) {
|
||||||
|
std::unordered_map<uint8_t, unsigned> biomes;
|
||||||
|
for (int16_t dx = -BIOME_SMOOTH; dx <= BIOME_SMOOTH; dx++) {
|
||||||
|
for (int16_t dz = -BIOME_SMOOTH; dz <= BIOME_SMOOTH; dz++) {
|
||||||
if (std::abs(dx) + std::abs(dz) > BIOME_SMOOTH)
|
if (std::abs(dx) + std::abs(dz) > BIOME_SMOOTH)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -85,11 +88,11 @@ static Resource::Color collectColors(size_t x, size_t z, const World::Block &blo
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource::FloatColor c = {};
|
Resource::FloatColor c = {};
|
||||||
size_t total = 0;
|
unsigned total = 0;
|
||||||
|
|
||||||
for (const auto &e : biomes) {
|
for (const auto &e : biomes) {
|
||||||
uint8_t biome = e.first;
|
uint8_t biome = e.first;
|
||||||
size_t count = e.second;
|
unsigned count = e.second;
|
||||||
|
|
||||||
if (biome == 0xff)
|
if (biome == 0xff)
|
||||||
continue;
|
continue;
|
||||||
|
@ -104,14 +107,14 @@ static Resource::Color collectColors(size_t x, size_t z, const World::Block &blo
|
||||||
return (1.0f / total) * c;
|
return (1.0f / total) * c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z,
|
static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], chunk_idx_t X, chunk_idx_t Z,
|
||||||
const World::ChunkData *data, const std::unique_ptr<uint8_t[]> biomemaps[3][3]
|
const World::ChunkData *data, const std::unique_ptr<uint8_t[]> biomemaps[3][3]
|
||||||
) {
|
) {
|
||||||
World::Chunk chunk(data);
|
World::Chunk chunk(data);
|
||||||
World::Chunk::Heightmap layer = chunk.getTopLayer(World::Chunk::WITH_DEPTH);
|
World::Chunk::Heightmap layer = chunk.getTopLayer(World::Chunk::WITH_DEPTH);
|
||||||
|
|
||||||
for (size_t x = 0; x < World::Chunk::SIZE; x++) {
|
for (block_idx_t x = 0; x < World::Chunk::SIZE; x++) {
|
||||||
for (size_t z = 0; z < World::Chunk::SIZE; z++) {
|
for (block_idx_t z = 0; z < World::Chunk::SIZE; z++) {
|
||||||
size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x;
|
size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x;
|
||||||
const World::Chunk::Height &height = layer.v[x][z];
|
const World::Chunk::Height &height = layer.v[x][z];
|
||||||
World::Block block = chunk.getBlock(x, height, z);
|
World::Block block = chunk.getBlock(x, height, z);
|
||||||
|
@ -261,7 +264,7 @@ static void makeBiome(const std::string ®iondir, const std::string &outputdir
|
||||||
std::unique_ptr<uint8_t[]> biomemap(new uint8_t[DIM*DIM]);
|
std::unique_ptr<uint8_t[]> biomemap(new uint8_t[DIM*DIM]);
|
||||||
std::memset(biomemap.get(), 0xff, DIM*DIM);
|
std::memset(biomemap.get(), 0xff, DIM*DIM);
|
||||||
|
|
||||||
World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) {
|
World::Region::visitChunks(input.c_str(), [&] (chunk_idx_t X, chunk_idx_t Z, const World::ChunkData *chunk) {
|
||||||
addChunkBiome(biomemap.get(), X, Z, chunk);
|
addChunkBiome(biomemap.get(), X, Z, chunk);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -289,8 +292,8 @@ static void makeMap(const std::string ®iondir, const std::string &outputdir,
|
||||||
if (intime == INT64_MIN)
|
if (intime == INT64_MIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
for (size_t j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
biomenames[i][j] = outputdir + "/biome/" + formatTileName(x + i - 1, z + j - 1, "png");
|
biomenames[i][j] = outputdir + "/biome/" + formatTileName(x + i - 1, z + j - 1, "png");
|
||||||
intime = std::max(intime, getModTime(biomenames[i][j]));
|
intime = std::max(intime, getModTime(biomenames[i][j]));
|
||||||
}
|
}
|
||||||
|
@ -304,8 +307,8 @@ static void makeMap(const std::string ®iondir, const std::string &outputdir,
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::unique_ptr<uint8_t[]> biomemaps[3][3];
|
std::unique_ptr<uint8_t[]> biomemaps[3][3];
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
for (size_t j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
biomemaps[i][j].reset(new uint8_t[DIM*DIM]);
|
biomemaps[i][j].reset(new uint8_t[DIM*DIM]);
|
||||||
std::memset(biomemaps[i][j].get(), 0, DIM*DIM);
|
std::memset(biomemaps[i][j].get(), 0, DIM*DIM);
|
||||||
|
|
||||||
|
@ -320,7 +323,7 @@ static void makeMap(const std::string ®iondir, const std::string &outputdir,
|
||||||
std::unique_ptr<uint8_t[]> lightmap(new uint8_t[2*DIM*DIM]);
|
std::unique_ptr<uint8_t[]> lightmap(new uint8_t[2*DIM*DIM]);
|
||||||
std::memset(lightmap.get(), 0, 2*DIM*DIM);
|
std::memset(lightmap.get(), 0, 2*DIM*DIM);
|
||||||
|
|
||||||
World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) {
|
World::Region::visitChunks(input.c_str(), [&] (chunk_idx_t X, chunk_idx_t Z, const World::ChunkData *chunk) {
|
||||||
addChunk(image.get(), lightmap.get(), X, Z, chunk, biomemaps);
|
addChunk(image.get(), lightmap.get(), X, Z, chunk, biomemaps);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -355,7 +358,7 @@ static bool makeMipmap(const std::string &dir, size_t level, int x, int z, PNG::
|
||||||
const char *se = se_str.c_str();
|
const char *se = se_str.c_str();
|
||||||
|
|
||||||
int64_t t = INT64_MIN;
|
int64_t t = INT64_MIN;
|
||||||
size_t count = 0;
|
unsigned count = 0;
|
||||||
for (auto name : {&nw, &ne, &sw, &se}) {
|
for (auto name : {&nw, &ne, &sw, &se}) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
if (stat(*name, &s) < 0) {
|
if (stat(*name, &s) < 0) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, 2018, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
Copyright (c) 2019, Roman Shishkin <spark@uwtech.org>
|
Copyright (c) 2019, Roman Shishkin <spark@uwtech.org>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,6 @@
|
||||||
#include "Biome.hpp"
|
#include "Biome.hpp"
|
||||||
|
|
||||||
#include "BlockType.hpp"
|
#include "BlockType.hpp"
|
||||||
#include "../Util.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace MinedMap {
|
namespace MinedMap {
|
||||||
|
@ -42,7 +41,7 @@ FloatColor Biome::getFoliageColor(float temp, float rain) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FloatColor Biome::getBlockColor(const BlockType *type, unsigned height) const {
|
FloatColor Biome::getBlockColor(const BlockType *type, y_idx_t height) const {
|
||||||
FloatColor c = {
|
FloatColor c = {
|
||||||
float(type->color.r),
|
float(type->color.r),
|
||||||
float(type->color.g),
|
float(type->color.g),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Color.hpp"
|
#include "Color.hpp"
|
||||||
|
#include "../Util.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace MinedMap {
|
namespace MinedMap {
|
||||||
|
@ -30,7 +31,7 @@ public:
|
||||||
Biome(float temp0, float rain0, FloatColor water0 = {0.247f, 0.463f, 0.894f})
|
Biome(float temp0, float rain0, FloatColor water0 = {0.247f, 0.463f, 0.894f})
|
||||||
: temp(temp0), rain(rain0), water(water0) {}
|
: temp(temp0), rain(rain0), water(water0) {}
|
||||||
|
|
||||||
FloatColor getBlockColor(const BlockType *type, unsigned height) const;
|
FloatColor getBlockColor(const BlockType *type, y_idx_t height) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const Biome *const BIOME_DEFAULT;
|
extern const Biome *const BIOME_DEFAULT;
|
||||||
|
|
15
src/Util.hpp
15
src/Util.hpp
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -25,4 +26,16 @@ static inline float clamp(float v, float min, float max) {
|
||||||
return std::max(std::min(v, max), min);
|
return std::max(std::min(v, max), min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A block coordinate relative to a chunk/section (X/Y/Z)
|
||||||
|
typedef uint8_t block_idx_t;
|
||||||
|
// A section index in a chunk (Y)
|
||||||
|
typedef uint8_t section_idx_t;
|
||||||
|
// A chunk coordinate relative to a region (X/Z)
|
||||||
|
typedef uint8_t chunk_idx_t;
|
||||||
|
|
||||||
|
// A block coordinate relative to a region (X/Z)
|
||||||
|
typedef uint16_t region_block_idx_t;
|
||||||
|
// A block coordinate (Y)
|
||||||
|
typedef uint16_t y_idx_t;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ namespace World {
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
const Resource::BlockType *type;
|
const Resource::BlockType *type;
|
||||||
unsigned depth;
|
y_idx_t depth;
|
||||||
uint8_t blockLight;
|
uint8_t blockLight;
|
||||||
|
|
||||||
bool isVisible() const {
|
bool isVisible() const {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015-2019, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -42,13 +42,13 @@ Chunk::Chunk(const ChunkData *data) {
|
||||||
for (auto &sTag : *sectionsTag) {
|
for (auto &sTag : *sectionsTag) {
|
||||||
auto s = std::dynamic_pointer_cast<const NBT::CompoundTag>(sTag);
|
auto s = std::dynamic_pointer_cast<const NBT::CompoundTag>(sTag);
|
||||||
std::unique_ptr<Section> section = Section::makeSection(s, dataVersion);
|
std::unique_ptr<Section> section = Section::makeSection(s, dataVersion);
|
||||||
size_t Y = section->getY();
|
section_idx_t Y = section->getY();
|
||||||
sections.resize(Y);
|
sections.resize(Y);
|
||||||
sections.push_back(std::move(section));
|
sections.push_back(std::move(section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Chunk::getBiome(size_t x, size_t y, size_t z) const {
|
uint8_t Chunk::getBiome(block_idx_t x, y_idx_t y, block_idx_t z) const {
|
||||||
if (x > SIZE || y > MAXY || z > SIZE)
|
if (x > SIZE || y > MAXY || z > SIZE)
|
||||||
throw std::invalid_argument("corrupt chunk data");
|
throw std::invalid_argument("corrupt chunk data");
|
||||||
|
|
||||||
|
@ -62,19 +62,19 @@ uint8_t Chunk::getBiome(size_t x, size_t y, size_t z) const {
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block Chunk::getBlock(size_t x, Chunk::Height height, size_t z) const {
|
Block Chunk::getBlock(block_idx_t x, Chunk::Height height, block_idx_t z) const {
|
||||||
Block block = {};
|
Block block = {};
|
||||||
|
|
||||||
block.depth = height.depth;
|
block.depth = height.depth;
|
||||||
|
|
||||||
size_t Y = height.y / SIZE;
|
section_idx_t Y = height.y / SIZE;
|
||||||
size_t y = height.y % SIZE;
|
block_idx_t y = height.y % SIZE;
|
||||||
|
|
||||||
if (Y < sections.size() && sections[Y])
|
if (Y < sections.size() && sections[Y])
|
||||||
block.type = sections[Y]->getBlockStateAt(x, y, z);
|
block.type = sections[Y]->getBlockStateAt(x, y, z);
|
||||||
|
|
||||||
size_t Yt = (height.y + 1) / SIZE;
|
section_idx_t Yt = (height.y + 1) / SIZE;
|
||||||
size_t yt = (height.y + 1) % SIZE;
|
block_idx_t yt = (height.y + 1) % SIZE;
|
||||||
|
|
||||||
if (Yt < sections.size() && sections[Yt])
|
if (Yt < sections.size() && sections[Yt])
|
||||||
block.blockLight = sections[Yt]->getBlockLightAt(x, yt, z);
|
block.blockLight = sections[Yt]->getBlockLightAt(x, yt, z);
|
||||||
|
@ -82,7 +82,10 @@ Block Chunk::getBlock(size_t x, Chunk::Height height, size_t z) const {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Chunk::getHeight(Chunk::Height *height, const Section *section, size_t x, size_t y, size_t z, int flags) const {
|
bool Chunk::getHeight(
|
||||||
|
Chunk::Height *height, const Section *section,
|
||||||
|
block_idx_t x, block_idx_t y, block_idx_t z, int flags
|
||||||
|
) const {
|
||||||
if (height->depth > 0)
|
if (height->depth > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -108,10 +111,10 @@ bool Chunk::getHeight(Chunk::Height *height, const Section *section, size_t x, s
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk::Heightmap Chunk::getTopLayer(int flags) const {
|
Chunk::Heightmap Chunk::getTopLayer(int flags) const {
|
||||||
size_t done = 0;
|
uint32_t done = 0;
|
||||||
Heightmap ret = {};
|
Heightmap ret = {};
|
||||||
|
|
||||||
for (ssize_t Y = sections.size() - 1; Y >= 0; Y--) {
|
for (int16_t Y = sections.size() - 1; Y >= 0; Y--) {
|
||||||
if (done == SIZE*SIZE)
|
if (done == SIZE*SIZE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -120,12 +123,12 @@ Chunk::Heightmap Chunk::getTopLayer(int flags) const {
|
||||||
|
|
||||||
const Section *section = sections[Y].get();
|
const Section *section = sections[Y].get();
|
||||||
|
|
||||||
for (ssize_t y = SIZE-1; y >= 0; y--) {
|
for (int8_t y = SIZE-1; y >= 0; y--) {
|
||||||
if (done == SIZE*SIZE)
|
if (done == SIZE*SIZE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (size_t z = 0; z < SIZE; z++) {
|
for (block_idx_t z = 0; z < SIZE; z++) {
|
||||||
for (size_t x = 0; x < SIZE; x++) {
|
for (block_idx_t x = 0; x < SIZE; x++) {
|
||||||
if (getHeight(&ret.v[x][z], section, x, y, z, flags))
|
if (getHeight(&ret.v[x][z], section, x, y, z, flags))
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015-2018, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -24,19 +24,25 @@ namespace World {
|
||||||
|
|
||||||
class Chunk {
|
class Chunk {
|
||||||
public:
|
public:
|
||||||
static const size_t SIZE = Section::SIZE;
|
// Number of blocks in a chunk in x/z dimensions
|
||||||
static const size_t MAXY = 256;
|
static const uint32_t SIZE = Section::SIZE;
|
||||||
|
// Maximum Y value
|
||||||
|
static const y_idx_t MAXY = 256;
|
||||||
|
|
||||||
static const size_t BGROUP = 4;
|
// Since Minecraft 1.15, biome information is stored for
|
||||||
static const size_t BSIZE = SIZE / BGROUP;
|
// 4x4x4 block groups
|
||||||
static const size_t BMAXY = MAXY / BGROUP;
|
static const uint32_t BGROUP = 4;
|
||||||
|
// Number of biome values in a chunk in x/z dimensions
|
||||||
|
static const uint32_t BSIZE = SIZE / BGROUP;
|
||||||
|
// Number of biome values in a chunk in y dimension
|
||||||
|
static const uint32_t BMAXY = MAXY / BGROUP;
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
static const int WITH_DEPTH = (1 << 0);
|
static const int WITH_DEPTH = (1 << 0);
|
||||||
|
|
||||||
struct Height {
|
struct Height {
|
||||||
unsigned y;
|
y_idx_t y;
|
||||||
unsigned depth;
|
y_idx_t depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Heightmap {
|
struct Heightmap {
|
||||||
|
@ -51,10 +57,13 @@ 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;
|
||||||
|
|
||||||
bool getHeight(Height *height, const Section *section, size_t x, size_t y, size_t z, int flags) const;
|
bool getHeight(
|
||||||
|
Height *height, const Section *section,
|
||||||
|
block_idx_t x, block_idx_t y, block_idx_t z, int flags
|
||||||
|
) const;
|
||||||
|
|
||||||
const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const {
|
const Resource::BlockType * getBlockStateAt(block_idx_t x, y_idx_t y, block_idx_t z) const {
|
||||||
size_t Y = y / SIZE;
|
section_idx_t Y = y / SIZE;
|
||||||
|
|
||||||
if (Y >= sections.size() || !sections[Y])
|
if (Y >= sections.size() || !sections[Y])
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -70,8 +79,8 @@ public:
|
||||||
return *level;
|
return *level;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBiome(size_t x, size_t y, size_t z) const;
|
uint8_t getBiome(block_idx_t x, y_idx_t y, block_idx_t z) const;
|
||||||
Block getBlock(size_t x, Height y, size_t z) const;
|
Block getBlock(block_idx_t x, Height y, block_idx_t z) const;
|
||||||
|
|
||||||
Heightmap getTopLayer(int flags) const;
|
Heightmap getTopLayer(int flags) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -18,16 +18,16 @@ namespace World {
|
||||||
Region::ChunkMap Region::processHeader(const uint8_t header[4096]) {
|
Region::ChunkMap Region::processHeader(const uint8_t header[4096]) {
|
||||||
ChunkMap map;
|
ChunkMap map;
|
||||||
|
|
||||||
for (size_t z = 0; z < 32; z++) {
|
for (chunk_idx_t z = 0; z < 32; z++) {
|
||||||
for (size_t x = 0; x < 32; x++) {
|
for (chunk_idx_t x = 0; x < 32; x++) {
|
||||||
const uint8_t *p = &header[128*z + x*4];
|
const uint8_t *p = &header[128*z + x*4];
|
||||||
|
|
||||||
size_t offset = (p[0] << 16) | (p[1] << 8) | p[2];
|
uint32_t offset = (p[0] << 16) | (p[1] << 8) | p[2];
|
||||||
|
|
||||||
if (!offset)
|
if (!offset)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t len = p[3];
|
uint8_t len = p[3];
|
||||||
|
|
||||||
map.emplace(offset, ChunkDesc(x, z, len));
|
map.emplace(offset, ChunkDesc(x, z, len));
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,9 @@ void Region::visitChunks(const char *filename, const ChunkVisitor &visitor) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t x, z, len;
|
chunk_idx_t x = std::get<0>(it->second);
|
||||||
std::tie(x, z, len) = it->second;
|
chunk_idx_t z = std::get<1>(it->second);
|
||||||
|
size_t len = std::get<2>(it->second);
|
||||||
|
|
||||||
if (seen[x][z])
|
if (seen[x][z])
|
||||||
throw std::invalid_argument("duplicate chunk");
|
throw std::invalid_argument("duplicate chunk");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -21,15 +21,16 @@ namespace World {
|
||||||
|
|
||||||
class Region {
|
class Region {
|
||||||
public:
|
public:
|
||||||
static const size_t SIZE = 32;
|
// Number of chunks in a region in each dimension
|
||||||
|
static const uint32_t SIZE = 32;
|
||||||
|
|
||||||
typedef std::function<void (size_t, size_t, const ChunkData *)> ChunkVisitor;
|
typedef std::function<void (chunk_idx_t, chunk_idx_t, const ChunkData *)> ChunkVisitor;
|
||||||
|
|
||||||
Region() = delete;
|
Region() = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::tuple<size_t, size_t, size_t> ChunkDesc;
|
typedef std::tuple<chunk_idx_t, chunk_idx_t, uint8_t> ChunkDesc;
|
||||||
typedef std::unordered_map<size_t, ChunkDesc> ChunkMap;
|
typedef std::unordered_map<uint32_t, ChunkDesc> ChunkMap;
|
||||||
|
|
||||||
static ChunkMap processHeader(const uint8_t header[4096]);
|
static ChunkMap processHeader(const uint8_t header[4096]);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015-2019, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
||||||
#include "Section.hpp"
|
#include "Section.hpp"
|
||||||
#include "../NBT/ByteTag.hpp"
|
#include "../NBT/ByteTag.hpp"
|
||||||
#include "../NBT/StringTag.hpp"
|
#include "../NBT/StringTag.hpp"
|
||||||
#include "../Util.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
@ -21,7 +20,7 @@ Section::Section(const std::shared_ptr<const NBT::CompoundTag> §ion) {
|
||||||
blockLight = section->get<NBT::ByteArrayTag>("BlockLight");
|
blockLight = section->get<NBT::ByteArrayTag>("BlockLight");
|
||||||
}
|
}
|
||||||
|
|
||||||
const Resource::BlockType * Section::getBlockStateAt(size_t, size_t, size_t) const {
|
const Resource::BlockType * Section::getBlockStateAt(block_idx_t, block_idx_t, block_idx_t) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ std::unique_ptr<Section> Section::makeSection(const std::shared_ptr<const NBT::C
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Resource::BlockType * LegacySection::getBlockStateAt(size_t x, size_t y, size_t z) const {
|
const Resource::BlockType * LegacySection::getBlockStateAt(block_idx_t x, block_idx_t y, block_idx_t z) const {
|
||||||
uint8_t type = getBlockAt(x, y, z);
|
uint8_t type = getBlockAt(x, y, z);
|
||||||
uint8_t data = getDataAt(x, y, z);
|
uint8_t data = getDataAt(x, y, z);
|
||||||
|
|
||||||
|
@ -97,7 +96,7 @@ PaletteSection::PaletteSection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Resource::BlockType * PaletteSection::getBlockStateAt(size_t x, size_t y, size_t z) const {
|
const Resource::BlockType * PaletteSection::getBlockStateAt(block_idx_t x, block_idx_t y, block_idx_t z) const {
|
||||||
size_t index = getIndex(x, y, z);
|
size_t index = getIndex(x, y, z);
|
||||||
size_t bitIndex;
|
size_t bitIndex;
|
||||||
|
|
||||||
|
@ -110,7 +109,7 @@ const Resource::BlockType * PaletteSection::getBlockStateAt(size_t x, size_t y,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pos = bitIndex >> 3;
|
size_t pos = bitIndex >> 3;
|
||||||
size_t shift = bitIndex & 7;
|
unsigned shift = bitIndex & 7;
|
||||||
uint16_t mask = (1u << bits) - 1;
|
uint16_t mask = (1u << bits) - 1;
|
||||||
|
|
||||||
uint32_t v = blockStates->getPointer()[mangleByteIndex(pos)];
|
uint32_t v = blockStates->getPointer()[mangleByteIndex(pos)];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2015-2019, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2015-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
#include "../NBT/ListTag.hpp"
|
#include "../NBT/ListTag.hpp"
|
||||||
#include "../NBT/LongArrayTag.hpp"
|
#include "../NBT/LongArrayTag.hpp"
|
||||||
#include "../Resource/BlockType.hpp"
|
#include "../Resource/BlockType.hpp"
|
||||||
|
#include "../Util.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -23,21 +24,22 @@ namespace World {
|
||||||
|
|
||||||
class Section {
|
class Section {
|
||||||
public:
|
public:
|
||||||
static const size_t SIZE = 16;
|
// Number of blocks in a section in each dimension
|
||||||
|
static const uint32_t SIZE = 16;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t Y;
|
section_idx_t Y;
|
||||||
std::shared_ptr<const NBT::ByteArrayTag> blockLight;
|
std::shared_ptr<const NBT::ByteArrayTag> blockLight;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static size_t getIndex(size_t x, size_t y, size_t z) {
|
static size_t getIndex(block_idx_t x, block_idx_t y, block_idx_t z) {
|
||||||
if (x >= SIZE || y >= SIZE || z >= SIZE)
|
if (x >= SIZE || y >= SIZE || z >= SIZE)
|
||||||
throw std::range_error("Chunk::getIndex(): bad coordinates");
|
throw std::range_error("Chunk::getIndex(): bad coordinates");
|
||||||
|
|
||||||
return SIZE*SIZE*y + SIZE*z + x;
|
return SIZE*SIZE*y + SIZE*z + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t getHalf(const uint8_t *v, size_t x, size_t y, size_t z) {
|
static uint8_t getHalf(const uint8_t *v, block_idx_t x, block_idx_t y, block_idx_t z) {
|
||||||
size_t i = getIndex(x, y, z);
|
size_t i = getIndex(x, y, z);
|
||||||
|
|
||||||
if (i % 2)
|
if (i % 2)
|
||||||
|
@ -51,11 +53,11 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual ~Section() {}
|
virtual ~Section() {}
|
||||||
|
|
||||||
size_t getY() const { return Y; };
|
section_idx_t getY() const { return Y; };
|
||||||
|
|
||||||
virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const;
|
virtual const Resource::BlockType * getBlockStateAt(block_idx_t x, block_idx_t y, block_idx_t z) const;
|
||||||
|
|
||||||
uint8_t getBlockLightAt(size_t x, size_t y, size_t z) const {
|
uint8_t getBlockLightAt(block_idx_t x, block_idx_t y, block_idx_t z) const {
|
||||||
if (!blockLight)
|
if (!blockLight)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -71,11 +73,11 @@ private:
|
||||||
std::shared_ptr<const NBT::ByteArrayTag> data;
|
std::shared_ptr<const NBT::ByteArrayTag> data;
|
||||||
|
|
||||||
|
|
||||||
uint8_t getBlockAt(size_t x, size_t y, size_t z) const {
|
uint8_t getBlockAt(block_idx_t x, block_idx_t y, block_idx_t z) const {
|
||||||
return blocks->getValue(getIndex(x, y, z));
|
return blocks->getValue(getIndex(x, y, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getDataAt(size_t x, size_t y, size_t z) const {
|
uint8_t getDataAt(block_idx_t x, block_idx_t y, block_idx_t z) const {
|
||||||
return getHalf(data->getPointer(), x, y, z);
|
return getHalf(data->getPointer(), x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +88,7 @@ public:
|
||||||
std::shared_ptr<const NBT::ByteArrayTag> &&data0
|
std::shared_ptr<const NBT::ByteArrayTag> &&data0
|
||||||
) : Section(section), blocks(blocks0), data(data0) {}
|
) : Section(section), blocks(blocks0), data(data0) {}
|
||||||
|
|
||||||
virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const;
|
virtual const Resource::BlockType * getBlockStateAt(block_idx_t x, block_idx_t y, block_idx_t z) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PaletteSection : public Section {
|
class PaletteSection : public Section {
|
||||||
|
@ -111,7 +113,7 @@ public:
|
||||||
uint32_t dataVersion0
|
uint32_t dataVersion0
|
||||||
);
|
);
|
||||||
|
|
||||||
virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const;
|
virtual const Resource::BlockType * getBlockStateAt(block_idx_t x, block_idx_t y, block_idx_t z) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: BSD-2-Clause
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2018, Matthias Schiffer <mschiffer@universe-factory.net>
|
Copyright (c) 2018-2021, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ int main(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
World::Region::visitChunks(argv[1], [&] (size_t X, size_t Z, const World::ChunkData *chunk) {
|
World::Region::visitChunks(argv[1], [&] (chunk_idx_t X, chunk_idx_t Z, const World::ChunkData *chunk) {
|
||||||
std::cout << "Chunk(" << X << ", " << Z << "): "
|
std::cout << "Chunk(" << X << ", " << Z << "): "
|
||||||
<< chunk->getRoot() << std::endl;
|
<< chunk->getRoot() << std::endl;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue