BlockChunks now use Run Index Encoding, 80% reduction in mem usage.
parent
c209b2a372
commit
ee94e691ae
|
@ -56,7 +56,6 @@ include_directories(
|
|||
lib/header/json/include
|
||||
)
|
||||
|
||||
|
||||
add_subdirectory(src)
|
||||
add_executable(${MAIN_EXEC_NAME} src/Main.cpp)
|
||||
target_link_libraries(${MAIN_EXEC_NAME} Zepha_Core)
|
||||
|
@ -76,6 +75,11 @@ target_compile_definitions(${MAIN_EXEC_NAME} PUBLIC SOL_ALL_SAFETIES_ON)
|
|||
# Test Build
|
||||
add_subdirectory(test)
|
||||
add_executable(${TEST_EXEC_NAME} test/Main.cpp)
|
||||
|
||||
target_link_libraries(${TEST_EXEC_NAME} Zepha_Core)
|
||||
target_link_libraries(${TEST_EXEC_NAME} Zepha_Test)
|
||||
|
||||
target_include_directories(${TEST_EXEC_NAME} PRIVATE ${GLFW_HEADERS})
|
||||
target_compile_definitions(${TEST_EXEC_NAME} PUBLIC SOL_ALL_SAFETIES_ON)
|
||||
target_link_libraries(${TEST_EXEC_NAME} ${LUA_LIB})
|
||||
target_link_libraries (${TEST_EXEC_NAME} z)
|
||||
target_link_libraries(${TEST_EXEC_NAME} ${ENET_LIB})
|
|
@ -158,30 +158,54 @@ void MapGen::buildElevationMap(chunk_partials_map& chunks, chunk_partial& chunk)
|
|||
void MapGen::generateBlocks(chunk_partial& chunk) {
|
||||
glm::ivec3 lp {};
|
||||
|
||||
for (unsigned short i = 0; i < 256; i++) {
|
||||
unsigned short x = i / 16;
|
||||
unsigned short z = i % 16;
|
||||
auto dupe = std::make_unique<BlockChunk>(*chunk.second);
|
||||
|
||||
lp = {x, 0, z};
|
||||
auto& biome = biomes.getBiomeAt(chunk.first->temperature.get(lp), chunk.first->humidity.get(lp), chunk.first->roughness.get(lp));
|
||||
chunk.second->blocks = {};
|
||||
chunk.second->biomes = {};
|
||||
|
||||
for (unsigned short y = 0; y < 16; y++) {
|
||||
lp.y = y;
|
||||
unsigned short ind = Space::Block::index(lp);
|
||||
std::array<std::array<unsigned short, 16>, 16> biomeArray {};
|
||||
for (unsigned short x = 0; x < 16; x++) {
|
||||
biomeArray[x] = {};
|
||||
for (unsigned short z = 0; z < 16; z++) {
|
||||
lp = {x, 0, z};
|
||||
biomeArray[x][z] = biomes.getBiomeAt(
|
||||
chunk.first->temperature.get(lp),
|
||||
chunk.first->humidity.get(lp),
|
||||
chunk.first->roughness.get(lp)).index;
|
||||
}
|
||||
}
|
||||
|
||||
chunk.second->biomes[ind] = biome.index;
|
||||
for (unsigned short m = 0; m < 4096; m++) {
|
||||
Vec::indAssignVec(m, lp);
|
||||
auto& biome = biomes.biomeFromId(biomeArray[lp.x][lp.z]);
|
||||
|
||||
if (chunk.second->blocks[ind] != DefinitionAtlas::INVALID) continue;
|
||||
unsigned int storedBlock = (chunk.second->blocks.size() <= 0 ? -1 : chunk.second->blocks[chunk.second->blocks.size() - 1]);
|
||||
unsigned int storedBiome = (chunk.second->biomes.size() <= 0 ? -1 : chunk.second->biomes[chunk.second->biomes.size() - 1]);
|
||||
|
||||
int d = std::floor(chunk.first->depth[ind]);
|
||||
chunk.second->blocks[ind]
|
||||
if (biome.index != storedBiome) {
|
||||
chunk.second->biomes.emplace_back(m);
|
||||
chunk.second->biomes.emplace_back(biome.index);
|
||||
}
|
||||
|
||||
// if (chunk.second->blocks[ind] != DefinitionAtlas::INVALID) continue;
|
||||
|
||||
int d = std::floor(chunk.first->depth[m]);
|
||||
unsigned int targetBlock
|
||||
= d <= 1 ? DefinitionAtlas::AIR
|
||||
: d <= 2 ? biome.topBlock
|
||||
: d <= 4 ? biome.soilBlock
|
||||
: biome.rockBlock;
|
||||
|
||||
if (targetBlock != storedBlock) {
|
||||
chunk.second->blocks.emplace_back(m);
|
||||
chunk.second->blocks.emplace_back(targetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
if (dupe->partial) for (unsigned short i = 0; i < 4096; i++) {
|
||||
unsigned int b = dupe->getBlock(i);
|
||||
if (b != DefinitionAtlas::INVALID) chunk.second->setBlock(i, b);
|
||||
}
|
||||
}
|
||||
|
||||
void MapGen::generateStructures(chunk_partials_map& chunks, chunk_partial& chunk) {
|
||||
|
@ -235,7 +259,9 @@ void MapGen::setBlock(glm::ivec3 worldPos, unsigned int block, MapGen::chunk_par
|
|||
if (chunks.count(chunkPos)) chunk = chunks.at(chunkPos).second;
|
||||
else {
|
||||
chunk = new BlockChunk();
|
||||
chunk->initializeEmpty();
|
||||
chunk->pos = chunkPos;
|
||||
chunk->partial = true;
|
||||
chunks.insert(std::pair<glm::ivec3, chunk_partial>{chunkPos, {new MapGenJob(), chunk}});
|
||||
}
|
||||
|
||||
|
@ -261,5 +287,6 @@ std::shared_ptr<BlockChunk> MapGen::combinePartials(std::shared_ptr<BlockChunk>
|
|||
}
|
||||
|
||||
res->generated = src->generated || res->generated;
|
||||
res->partial = !res->generated;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -28,10 +28,26 @@ MeshGenerator::MeshGenerator(MeshDetails* meshDetails, LocalDefs& defs, std::sha
|
|||
glm::vec3 vis;
|
||||
glm::vec3 check;
|
||||
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
BlockModel& model = hi ? atlas.blockFromId(chunk->getBlock(i)).model : atlas.blockFromId(chunk->getBlock(i)).farModel;
|
||||
const auto& blocks = chunk->cGetBlocks();
|
||||
const auto& biomes = chunk->cGetBiomes();
|
||||
|
||||
glm::vec3 biomeTint = defs.biomes.biomeFromId(chunk->getBiome(i)).biomeTint;
|
||||
unsigned short blockArrayPos = 0;
|
||||
unsigned int cBlock = blocks[blockArrayPos + 1];
|
||||
unsigned short biomeArrayPos = 0;
|
||||
unsigned short cBiome = biomes[biomeArrayPos + 1];
|
||||
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
if (blockArrayPos + 2 < blocks.size() && i >= blocks[blockArrayPos + 2]) {
|
||||
blockArrayPos += 2;
|
||||
cBlock = blocks[blockArrayPos + 1];
|
||||
}
|
||||
if (biomeArrayPos + 2 < biomes.size() && i >= biomes[biomeArrayPos + 2]) {
|
||||
biomeArrayPos += 2;
|
||||
cBiome = biomes[biomeArrayPos + 1];
|
||||
}
|
||||
|
||||
BlockModel& model = hi ? atlas.blockFromId(cBlock).model : atlas.blockFromId(cBlock).farModel;
|
||||
glm::vec3 biomeTint = defs.biomes.biomeFromId(cBiome).biomeTint;
|
||||
|
||||
if (model.visible) {
|
||||
Vec::indAssignVec(i, off);
|
||||
|
@ -82,7 +98,6 @@ MeshGenerator::MeshGenerator(MeshDetails* meshDetails, LocalDefs& defs, std::sha
|
|||
|
||||
BlockDef& MeshGenerator::getBlockAt(const glm::ivec3 &pos) {
|
||||
if (pos.x < 0 || pos.x >= 16 || pos.y < 0 || pos.y >= 16 || pos.z < 0 || pos.z >= 16) {
|
||||
|
||||
if (pos.x == 16) return atlas.blockFromId(adjacent[0]->getBlock(pos - glm::ivec3 {16, 0, 0}));
|
||||
if (pos.x == -1) return atlas.blockFromId(adjacent[1]->getBlock(pos + glm::ivec3 {16, 0, 0}));
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
#include <gzip/decompress.hpp>
|
||||
#include <gzip/utils.hpp>
|
||||
|
||||
BlockChunk::BlockChunk(const std::array<unsigned int, 4096>& blocks, const std::array<unsigned short, 4096>& biomes) :
|
||||
BlockChunk::BlockChunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
|
||||
BlockChunk(blocks, biomes, {0, 0, 0}) {}
|
||||
|
||||
BlockChunk::BlockChunk(const std::array<unsigned int, 4096>& blocks, const std::array<unsigned short, 4096>& biomes, glm::ivec3 pos) :
|
||||
BlockChunk::BlockChunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos) :
|
||||
blocks(std::move(blocks)),
|
||||
biomes(std::move(biomes)),
|
||||
pos(pos),
|
||||
|
@ -19,55 +19,134 @@ BlockChunk::BlockChunk(const std::array<unsigned int, 4096>& blocks, const std::
|
|||
calcNonAirBlocks();
|
||||
}
|
||||
|
||||
bool BlockChunk::setBlock(unsigned int ind, unsigned int blk) {
|
||||
// Exit early if no manipulation is needed.
|
||||
if (ind >= 4096) return false;
|
||||
|
||||
const unsigned int existing = getBlock(ind);
|
||||
if (existing == blk) return false;
|
||||
|
||||
// Deal with shouldHaveMesh
|
||||
if (blk == DefinitionAtlas::AIR) {
|
||||
if ((nonAirBlocks = fmax(nonAirBlocks - 1, 0)) == 0) {
|
||||
empty = true;
|
||||
shouldHaveMesh = false;
|
||||
}
|
||||
}
|
||||
else if (existing == DefinitionAtlas::AIR) {
|
||||
if (nonAirBlocks == 0) shouldHaveMesh = true;
|
||||
empty = false;
|
||||
nonAirBlocks++;
|
||||
}
|
||||
|
||||
if (ind == 0) {
|
||||
if (blocks[2] == ind + 1) {
|
||||
blocks[1] = blk;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
blocks.insert(blocks.begin() + 2, 2, ind);
|
||||
blocks[2] = 1;
|
||||
blocks[3] = blocks[1];
|
||||
blocks[1] = blk;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < blocks.size(); i += 2) {
|
||||
if (blocks[i] == ind) {
|
||||
// We found an index equating to the block we are going to be setting.
|
||||
if (blocks[i - 1] == blk) {
|
||||
// The last block strip is the same block ID as what we are setting,
|
||||
// So we should extend that strip.
|
||||
if (blocks.size() > i + 2 && blocks[i + 2] == ind + 1) {
|
||||
// The next block is one later, meaning we can simply remove this found block
|
||||
// To cause the next strip to cascade over its position.
|
||||
blocks.erase(blocks.begin() + i, blocks.begin() + i + 2);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// The next strip is multiple blocks over, so just add one to our found block index.
|
||||
blocks[i] += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The last strip is not the same block.
|
||||
if (blocks.size() > i + 2 && blocks[i + 2] == ind + 1) {
|
||||
// There is only one of our block, so we can just update its id.
|
||||
blocks[i + 1] = blk;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// The next strip is multiple blocks over, so we need to copy the previous block to the right
|
||||
// and then set our block into its place
|
||||
blocks.insert(blocks.begin() + i, 2, ind);
|
||||
blocks[i + 1] = blk;
|
||||
blocks[i + 2] = ind + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (blocks[i] > ind) {
|
||||
// We found a strip with an index *larger* than our ind.
|
||||
// We can assume the last strip is not our block, because the getBlock() catch would have caught that.
|
||||
if (blocks[i] == ind + 1) {
|
||||
if (blocks[i + 1] == blk) {
|
||||
// The next block over is the same, so we can just decrement our index by one.
|
||||
blocks[i] --;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// There is only one of our block to be placed, directly before our current strip
|
||||
blocks.insert(blocks.begin() + i, 2, ind);
|
||||
blocks[i + 1] = blk;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The next strip is multiple blocks over, so we need to insert both our block
|
||||
// *and* the previous strip's block after
|
||||
blocks.insert(blocks.begin() + i, 4, ind);
|
||||
blocks[i + 1] = blk;
|
||||
blocks[i + 2] = ind + 1;
|
||||
blocks[i + 3] = blocks[i - 1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Escaped the for loop, meaning there's no index greater than ours.
|
||||
// We will insert our index at the end of the array, and insert the previous block after
|
||||
// if we're not at the end of the chunk.
|
||||
blocks.push_back(ind);
|
||||
blocks.push_back(blk);
|
||||
|
||||
if (ind >= 4095) return true; // Don't add the reset if at the end of the chunk.
|
||||
|
||||
blocks.push_back(ind + 1);
|
||||
blocks.push_back(blocks[blocks.size() - 4]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<unsigned int> &BlockChunk::cGetBlocks() const {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
const std::vector<unsigned short> &BlockChunk::cGetBiomes() const {
|
||||
return biomes;
|
||||
}
|
||||
|
||||
Packet BlockChunk::serialize() {
|
||||
Serializer s;
|
||||
s.append(pos);
|
||||
|
||||
{
|
||||
unsigned int curr = blocks[0];
|
||||
unsigned int length = 1;
|
||||
std::string temp = Serializer().append(blocks).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
|
||||
std::vector<unsigned int> blocksRle;
|
||||
temp = Serializer().append(biomes).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
|
||||
for (int i = 1; i < 4096; i++) {
|
||||
if (blocks[i] == curr) length++;
|
||||
else {
|
||||
blocksRle.push_back(curr);
|
||||
blocksRle.push_back(length);
|
||||
length = 1;
|
||||
curr = blocks[i];
|
||||
}
|
||||
}
|
||||
blocksRle.push_back(curr);
|
||||
blocksRle.push_back(length);
|
||||
|
||||
std::string temp = Serializer().append(blocksRle).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
} {
|
||||
unsigned int curr = biomes[0];
|
||||
unsigned short length = 1;
|
||||
|
||||
std::vector<unsigned short> biomesRle;
|
||||
|
||||
for (int i = 1; i < 4096; i++) {
|
||||
if (biomes[i] == curr) length++;
|
||||
else {
|
||||
biomesRle.push_back(curr);
|
||||
biomesRle.push_back(length);
|
||||
length = 1;
|
||||
curr = biomes[i];
|
||||
}
|
||||
}
|
||||
biomesRle.push_back(curr);
|
||||
biomesRle.push_back(length);
|
||||
|
||||
std::string temp = Serializer().append(biomesRle).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
}
|
||||
|
||||
Packet p(PacketType::CHUNK);
|
||||
p.data = s.data;
|
||||
return p;
|
||||
return s.packet(PacketType::CHUNK);
|
||||
}
|
||||
|
||||
void BlockChunk::deserialize(Packet& packet) {
|
||||
|
@ -75,60 +154,39 @@ void BlockChunk::deserialize(Packet& packet) {
|
|||
|
||||
pos = d.read<glm::ivec3>();
|
||||
|
||||
{
|
||||
auto gzip = d.read<std::string>();
|
||||
if (!gzip::is_compressed(gzip.data(), gzip.length())) throw "Invalid Blocks GZip Data.";
|
||||
gzip = gzip::decompress(gzip.data(), gzip.length());
|
||||
auto gzip = d.read<std::string>();
|
||||
if (!gzip::is_compressed(gzip.data(), gzip.length())) throw "Invalid Blocks GZip Data.";
|
||||
gzip = gzip::decompress(gzip.data(), gzip.length());
|
||||
|
||||
std::vector<unsigned int> rle = Deserializer(gzip).read<std::vector<unsigned int>>();
|
||||
|
||||
this->empty = true;
|
||||
|
||||
int ind = 0;
|
||||
for (int i = 0; i < rle.size() / 2; i++) {
|
||||
unsigned int block = rle[i * 2];
|
||||
unsigned int count = rle[i * 2 + 1];
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
blocks[ind++] = block;
|
||||
if (block != 0) this->empty = false;
|
||||
if (ind >= 4096) goto biomes;
|
||||
}
|
||||
}
|
||||
}
|
||||
biomes: {}
|
||||
{
|
||||
auto gzip = d.read<std::string>();
|
||||
if (!gzip::is_compressed(gzip.data(), gzip.length())) throw "Invalid Biomes GZip Data.";
|
||||
gzip = gzip::decompress(gzip.data(), gzip.length());
|
||||
|
||||
std::vector<unsigned short> rle = Deserializer(gzip).read<std::vector<unsigned short>>();
|
||||
|
||||
int ind = 0;
|
||||
for (int i = 0; i < rle.size() / 2; i++) {
|
||||
unsigned int biome = rle[i * 2];
|
||||
unsigned int count = rle[i * 2 + 1];
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
biomes[ind++] = biome;
|
||||
if (ind >= 4096) goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
end: {}
|
||||
blocks = Deserializer(gzip).read<std::vector<unsigned int>>();
|
||||
calcNonAirBlocks();
|
||||
|
||||
gzip = d.read<std::string>();
|
||||
if (!gzip::is_compressed(gzip.data(), gzip.length())) throw "Invalid Biomes GZip Data.";
|
||||
gzip = gzip::decompress(gzip.data(), gzip.length());
|
||||
|
||||
biomes = Deserializer(gzip).read<std::vector<unsigned short>>();
|
||||
}
|
||||
|
||||
void BlockChunk::calcNonAirBlocks() {
|
||||
nonAirBlocks = 0;
|
||||
empty = true;
|
||||
|
||||
for (unsigned int block : blocks) {
|
||||
if (block > DefinitionAtlas::AIR) {
|
||||
for (unsigned int i = 0; i < blocks.size(); i += 2) {
|
||||
unsigned int cInd = blocks[i];
|
||||
unsigned int lInd = (i == 0 ? 0 : blocks[i - 2]);
|
||||
unsigned int blk = blocks[i + 1];
|
||||
|
||||
if (blk > DefinitionAtlas::AIR) {
|
||||
empty = false;
|
||||
nonAirBlocks++;
|
||||
nonAirBlocks += cInd - lInd;
|
||||
}
|
||||
}
|
||||
|
||||
shouldHaveMesh = !empty;
|
||||
}
|
||||
}
|
||||
|
||||
void BlockChunk::initializeEmpty() {
|
||||
blocks = {0, 0};
|
||||
biomes = {0, 0};
|
||||
}
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
class BlockChunk {
|
||||
public:
|
||||
BlockChunk() = default;
|
||||
explicit BlockChunk(const std::array<unsigned int, 4096>& blocks, const std::array<unsigned short, 4096>& biomes);
|
||||
BlockChunk(const std::array<unsigned int, 4096>& blocks, const std::array<unsigned short, 4096>& biomes, glm::ivec3 pos);
|
||||
explicit BlockChunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
|
||||
BlockChunk(const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes, glm::ivec3 pos);
|
||||
|
||||
inline bool setBlock(unsigned int ind, unsigned int blk);
|
||||
void initializeEmpty();
|
||||
|
||||
bool setBlock(unsigned int ind, unsigned int blk);
|
||||
inline bool setBlock(const glm::ivec3& pos, unsigned int blk);
|
||||
|
||||
inline unsigned int getBlock(unsigned int ind) const;
|
||||
|
@ -39,6 +41,9 @@ public:
|
|||
inline int getSunlight(unsigned int ind);
|
||||
inline int getBlocklight(unsigned int ind);
|
||||
|
||||
const std::vector<unsigned int>& cGetBlocks() const;
|
||||
const std::vector<unsigned short>& cGetBiomes() const;
|
||||
|
||||
Packet serialize();
|
||||
void deserialize(Packet& packet);
|
||||
|
||||
|
@ -49,37 +54,18 @@ public:
|
|||
|
||||
glm::ivec3 pos;
|
||||
private:
|
||||
std::array<unsigned int, 4096> blocks {};
|
||||
std::array<unsigned short, 4096> biomes {};
|
||||
std::vector<unsigned int> blocks {};
|
||||
std::vector<unsigned short> biomes {};
|
||||
std::array<unsigned char, 4096> lighting {};
|
||||
|
||||
bool empty = true;
|
||||
bool partial = false;
|
||||
unsigned short nonAirBlocks = 0;
|
||||
|
||||
friend class MapGen;
|
||||
void calcNonAirBlocks();
|
||||
};
|
||||
|
||||
inline bool BlockChunk::setBlock(unsigned int ind, unsigned int blk) {
|
||||
if (ind >= 4096) return false;
|
||||
if (blocks[ind] != blk) {
|
||||
if (blk == DefinitionAtlas::AIR) {
|
||||
if ((nonAirBlocks = fmax(nonAirBlocks - 1, 0)) == 0) {
|
||||
empty = true;
|
||||
shouldHaveMesh = false;
|
||||
}
|
||||
}
|
||||
else if (blocks[ind] == DefinitionAtlas::AIR) {
|
||||
if (nonAirBlocks == 0) shouldHaveMesh = true;
|
||||
empty = false;
|
||||
nonAirBlocks++;
|
||||
}
|
||||
blocks[ind] = blk;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool BlockChunk::setBlock(const glm::ivec3& pos, unsigned int blk) {
|
||||
if (pos.x > 15 || pos.x < 0 || pos.y > 15 || pos.y < 0 || pos.z > 15 || pos.z < 0) return false;
|
||||
return setBlock(Space::Block::index(pos), blk);
|
||||
|
@ -87,7 +73,10 @@ inline bool BlockChunk::setBlock(const glm::ivec3& pos, unsigned int blk) {
|
|||
|
||||
inline unsigned int BlockChunk::getBlock(unsigned int ind) const {
|
||||
if (ind >= 4096) return DefinitionAtlas::INVALID;
|
||||
return blocks[ind];
|
||||
for (unsigned int i = 0; i < blocks.size(); i += 2) {
|
||||
if (blocks[i] > ind) return blocks[i - 1];
|
||||
}
|
||||
return blocks[blocks.size() - 1];
|
||||
}
|
||||
|
||||
inline unsigned int BlockChunk::getBlock(const glm::ivec3& pos) const {
|
||||
|
@ -97,7 +86,10 @@ inline unsigned int BlockChunk::getBlock(const glm::ivec3& pos) const {
|
|||
|
||||
inline unsigned short BlockChunk::getBiome(unsigned int ind) const {
|
||||
if (ind >= 4096) return BiomeAtlas::INVALID;
|
||||
return biomes[ind];
|
||||
for (unsigned int i = 0; i < biomes.size(); i += 2) {
|
||||
if (biomes[i] > ind) return biomes[i - 1];
|
||||
}
|
||||
return biomes[biomes.size() - 1];
|
||||
}
|
||||
|
||||
inline unsigned short BlockChunk::getBiome(const glm::ivec3& pos) const {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 205 B |
|
@ -5,6 +5,7 @@
|
|||
#pragma clang diagnostic pop
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include <sol2/sol.hpp>
|
||||
|
||||
TEST_CASE("Catch2 Library", "[core]") {
|
||||
REQUIRE(true);
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include <iostream>
|
||||
#include "../../src/world/chunk/BlockChunk.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
|
||||
|
||||
TEST_CASE("BlockChunk", "[world]") {
|
||||
BlockChunk b;
|
||||
|
||||
SECTION("Lighting") {
|
||||
BlockChunk b;
|
||||
|
||||
b.setSunlight(1, 4);
|
||||
b.setSunlight(2, 1);
|
||||
b.setSunlight(3, 11);
|
||||
|
@ -42,4 +45,296 @@ TEST_CASE("BlockChunk", "[world]") {
|
|||
REQUIRE(b.getBlocklight(3000) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Blocks") {
|
||||
|
||||
SECTION("Exact index = 0, strip one after") {
|
||||
BlockChunk b {{0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(0, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 4);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 2);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block same, strip one after") {
|
||||
BlockChunk b {{0, 1, 1, 0, 2, 5}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 4);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 5);
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block same, strip two after") {
|
||||
BlockChunk b {{0, 1, 2, 0, 4, 5}, {}};
|
||||
|
||||
b.setBlock(2, 1);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 3);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 4);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
|
||||
SECTION("Exact index, last block same, strip one after AFTER two after") {
|
||||
b.setBlock(3, 1);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 4);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[4] == 4);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block same, no strip after") {
|
||||
BlockChunk b {{0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 4);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block different, strip one after") {
|
||||
BlockChunk b {{0, 1, 1, 0, 2, 5}, {}};
|
||||
|
||||
b.setBlock(1, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 2);
|
||||
REQUIRE(b.cGetBlocks()[4] == 2);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block different, strip two after") {
|
||||
BlockChunk b {{0, 1, 2, 0, 4, 5}, {}};
|
||||
|
||||
b.setBlock(2, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 8);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 2);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 0);
|
||||
REQUIRE(b.cGetBlocks()[6] == 4);
|
||||
REQUIRE(b.cGetBlocks()[7] == 5);
|
||||
|
||||
SECTION("Exact index, last block different, strip one after AFTER two after") {
|
||||
b.setBlock(3, 1);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 8);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 2);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 1);
|
||||
REQUIRE(b.cGetBlocks()[6] == 4);
|
||||
REQUIRE(b.cGetBlocks()[7] == 5);
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block same, strip one after AFTER two after") {
|
||||
b.setBlock(3, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 2);
|
||||
REQUIRE(b.cGetBlocks()[4] == 4);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Exact index, last block different, no strip after") {
|
||||
BlockChunk b {{0, 1, 1, 0}, {}};
|
||||
|
||||
b.setBlock(1, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 2);
|
||||
REQUIRE(b.cGetBlocks()[4] == 2);
|
||||
REQUIRE(b.cGetBlocks()[5] == 0);
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block same, strip one after") {
|
||||
BlockChunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 0);
|
||||
|
||||
// The function should exit early because of the getBlock check
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block same, strip two after") {
|
||||
BlockChunk b {{0, 1, 2, 0, 5, 5}, {}};
|
||||
|
||||
b.setBlock(3, 0);
|
||||
|
||||
// The function should exit early because of the getBlock check
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 5);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block same, no strip after") {
|
||||
BlockChunk b {{0, 1, 3, 0}, {}};
|
||||
|
||||
b.setBlock(1, 1);
|
||||
|
||||
// The function should exit early because of the getBlock check
|
||||
REQUIRE(b.cGetBlocks().size() == 4);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 3);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block different, strip one after") {
|
||||
SECTION("Indexed block different") {
|
||||
BlockChunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 8);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 2);
|
||||
REQUIRE(b.cGetBlocks()[5] == 2);
|
||||
REQUIRE(b.cGetBlocks()[6] == 3);
|
||||
REQUIRE(b.cGetBlocks()[7] == 5);
|
||||
}
|
||||
|
||||
SECTION("Indexed block same") {
|
||||
BlockChunk b {{0, 1, 1, 0, 3, 5}, {}};
|
||||
|
||||
b.setBlock(2, 5);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 1);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 2);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block different, strip three after") {
|
||||
BlockChunk b {{0, 1, 2, 0, 6, 6}, {}};
|
||||
|
||||
b.setBlock(3, 5);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 10);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
REQUIRE(b.cGetBlocks()[6] == 4);
|
||||
REQUIRE(b.cGetBlocks()[7] == 0);
|
||||
REQUIRE(b.cGetBlocks()[8] == 6);
|
||||
REQUIRE(b.cGetBlocks()[9] == 6);
|
||||
|
||||
SECTION("Greater index, last block same, strip one after AFTER three after") {
|
||||
b.setBlock(4, 5);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 10);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
REQUIRE(b.cGetBlocks()[6] == 5);
|
||||
REQUIRE(b.cGetBlocks()[7] == 0);
|
||||
REQUIRE(b.cGetBlocks()[8] == 6);
|
||||
REQUIRE(b.cGetBlocks()[9] == 6);
|
||||
}
|
||||
|
||||
SECTION("Greater index, last block different, strip one after AFTER three after") {
|
||||
b.setBlock(4, 2);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 12);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 3);
|
||||
REQUIRE(b.cGetBlocks()[5] == 5);
|
||||
REQUIRE(b.cGetBlocks()[6] == 4);
|
||||
REQUIRE(b.cGetBlocks()[7] == 2);
|
||||
REQUIRE(b.cGetBlocks()[8] == 5);
|
||||
REQUIRE(b.cGetBlocks()[9] == 0);
|
||||
REQUIRE(b.cGetBlocks()[10] == 6);
|
||||
REQUIRE(b.cGetBlocks()[11] == 6);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("No index found in loop, last block different, not end of chunk") {
|
||||
BlockChunk b {{0, 1, 2, 0}, {}};
|
||||
|
||||
b.setBlock(6, 6);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 8);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 6);
|
||||
REQUIRE(b.cGetBlocks()[5] == 6);
|
||||
REQUIRE(b.cGetBlocks()[6] == 7);
|
||||
REQUIRE(b.cGetBlocks()[7] == 0);
|
||||
}
|
||||
|
||||
SECTION("No index found in loop, last block different, end of chunk") {
|
||||
BlockChunk b {{0, 1, 2, 0}, {}};
|
||||
|
||||
b.setBlock(4095, 6);
|
||||
|
||||
REQUIRE(b.cGetBlocks().size() == 6);
|
||||
REQUIRE(b.cGetBlocks()[0] == 0);
|
||||
REQUIRE(b.cGetBlocks()[1] == 1);
|
||||
REQUIRE(b.cGetBlocks()[2] == 2);
|
||||
REQUIRE(b.cGetBlocks()[3] == 0);
|
||||
REQUIRE(b.cGetBlocks()[4] == 4095);
|
||||
REQUIRE(b.cGetBlocks()[5] == 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
Loading…
Reference in New Issue