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:
Matthias Schiffer 2021-11-17 12:25:26 +01:00
parent d4be401bcd
commit 457e993c92
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
13 changed files with 123 additions and 92 deletions

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -17,7 +17,7 @@ namespace World {
struct Block {
const Resource::BlockType *type;
unsigned depth;
y_idx_t depth;
uint8_t blockLight;
bool isVisible() const {

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -42,13 +42,13 @@ Chunk::Chunk(const ChunkData *data) {
for (auto &sTag : *sectionsTag) {
auto s = std::dynamic_pointer_cast<const NBT::CompoundTag>(sTag);
std::unique_ptr<Section> section = Section::makeSection(s, dataVersion);
size_t Y = section->getY();
section_idx_t Y = section->getY();
sections.resize(Y);
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)
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;
}
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.depth = height.depth;
size_t Y = height.y / SIZE;
size_t y = height.y % SIZE;
section_idx_t Y = height.y / SIZE;
block_idx_t y = height.y % SIZE;
if (Y < sections.size() && sections[Y])
block.type = sections[Y]->getBlockStateAt(x, y, z);
size_t Yt = (height.y + 1) / SIZE;
size_t yt = (height.y + 1) % SIZE;
section_idx_t Yt = (height.y + 1) / SIZE;
block_idx_t yt = (height.y + 1) % SIZE;
if (Yt < sections.size() && sections[Yt])
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;
}
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)
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 {
size_t done = 0;
uint32_t done = 0;
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)
break;
@ -120,12 +123,12 @@ Chunk::Heightmap Chunk::getTopLayer(int flags) const {
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)
break;
for (size_t z = 0; z < SIZE; z++) {
for (size_t x = 0; x < SIZE; x++) {
for (block_idx_t z = 0; z < SIZE; z++) {
for (block_idx_t x = 0; x < SIZE; x++) {
if (getHeight(&ret.v[x][z], section, x, y, z, flags))
done++;
}

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -24,19 +24,25 @@ namespace World {
class Chunk {
public:
static const size_t SIZE = Section::SIZE;
static const size_t MAXY = 256;
// Number of blocks in a chunk in x/z dimensions
static const uint32_t SIZE = Section::SIZE;
// Maximum Y value
static const y_idx_t MAXY = 256;
static const size_t BGROUP = 4;
static const size_t BSIZE = SIZE / BGROUP;
static const size_t BMAXY = MAXY / BGROUP;
// Since Minecraft 1.15, biome information is stored for
// 4x4x4 block groups
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
static const int WITH_DEPTH = (1 << 0);
struct Height {
unsigned y;
unsigned depth;
y_idx_t y;
y_idx_t depth;
};
struct Heightmap {
@ -51,10 +57,13 @@ private:
std::shared_ptr<const NBT::IntArrayTag> biomeIntsPre115;
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 {
size_t Y = y / SIZE;
const Resource::BlockType * getBlockStateAt(block_idx_t x, y_idx_t y, block_idx_t z) const {
section_idx_t Y = y / SIZE;
if (Y >= sections.size() || !sections[Y])
return nullptr;
@ -70,8 +79,8 @@ public:
return *level;
}
uint8_t getBiome(size_t x, size_t y, size_t z) const;
Block getBlock(size_t x, Height y, size_t z) const;
uint8_t getBiome(block_idx_t x, y_idx_t y, block_idx_t z) const;
Block getBlock(block_idx_t x, Height y, block_idx_t z) const;
Heightmap getTopLayer(int flags) const;
};

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -18,16 +18,16 @@ namespace World {
Region::ChunkMap Region::processHeader(const uint8_t header[4096]) {
ChunkMap map;
for (size_t z = 0; z < 32; z++) {
for (size_t x = 0; x < 32; x++) {
for (chunk_idx_t z = 0; z < 32; z++) {
for (chunk_idx_t x = 0; x < 32; x++) {
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)
continue;
size_t len = p[3];
uint8_t len = p[3];
map.emplace(offset, ChunkDesc(x, z, len));
}
@ -61,8 +61,9 @@ void Region::visitChunks(const char *filename, const ChunkVisitor &visitor) {
continue;
}
size_t x, z, len;
std::tie(x, z, len) = it->second;
chunk_idx_t x = std::get<0>(it->second);
chunk_idx_t z = std::get<1>(it->second);
size_t len = std::get<2>(it->second);
if (seen[x][z])
throw std::invalid_argument("duplicate chunk");

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -21,15 +21,16 @@ namespace World {
class Region {
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;
private:
typedef std::tuple<size_t, size_t, size_t> ChunkDesc;
typedef std::unordered_map<size_t, ChunkDesc> ChunkMap;
typedef std::tuple<chunk_idx_t, chunk_idx_t, uint8_t> ChunkDesc;
typedef std::unordered_map<uint32_t, ChunkDesc> ChunkMap;
static ChunkMap processHeader(const uint8_t header[4096]);

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -8,7 +8,6 @@
#include "Section.hpp"
#include "../NBT/ByteTag.hpp"
#include "../NBT/StringTag.hpp"
#include "../Util.hpp"
#include <cstdio>
@ -21,7 +20,7 @@ Section::Section(const std::shared_ptr<const NBT::CompoundTag> &section) {
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;
}
@ -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 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 bitIndex;
@ -110,7 +109,7 @@ const Resource::BlockType * PaletteSection::getBlockStateAt(size_t x, size_t y,
}
size_t pos = bitIndex >> 3;
size_t shift = bitIndex & 7;
unsigned shift = bitIndex & 7;
uint16_t mask = (1u << bits) - 1;
uint32_t v = blockStates->getPointer()[mangleByteIndex(pos)];

View file

@ -1,6 +1,6 @@
// 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.
*/
@ -13,6 +13,7 @@
#include "../NBT/ListTag.hpp"
#include "../NBT/LongArrayTag.hpp"
#include "../Resource/BlockType.hpp"
#include "../Util.hpp"
#include <cstdint>
#include <stdexcept>
@ -23,21 +24,22 @@ namespace World {
class Section {
public:
static const size_t SIZE = 16;
// Number of blocks in a section in each dimension
static const uint32_t SIZE = 16;
private:
size_t Y;
section_idx_t Y;
std::shared_ptr<const NBT::ByteArrayTag> blockLight;
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)
throw std::range_error("Chunk::getIndex(): bad coordinates");
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);
if (i % 2)
@ -51,11 +53,11 @@ protected:
public:
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)
return 0;
@ -71,11 +73,11 @@ private:
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));
}
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);
}
@ -86,7 +88,7 @@ public:
std::shared_ptr<const NBT::ByteArrayTag> &&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 {
@ -111,7 +113,7 @@ public:
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;
};
}