2022-09-25 23:05:56 +00:00
|
|
|
#include "chunk.hpp"
|
2022-09-27 17:35:49 +00:00
|
|
|
|
2022-09-25 23:05:56 +00:00
|
|
|
namespace app {
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK CONSTRUCTORS AND DECONSTUCTORS
|
|
|
|
//
|
2022-09-25 23:05:56 +00:00
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed)
|
2022-09-25 23:05:56 +00:00
|
|
|
: world_seed{world_seed},
|
|
|
|
chunk_seed{(world_seed * gridX) + (world_seed * gridZ) / 2},
|
|
|
|
gridX{gridX},
|
|
|
|
gridZ{gridZ} {
|
2022-09-27 17:35:49 +00:00
|
|
|
chunkMesh = nullptr;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
Chunk::~Chunk() {
|
|
|
|
if(worker.joinable())
|
|
|
|
worker.join();
|
2022-09-28 01:40:20 +00:00
|
|
|
xe::Model::deleteModel(chunkMesh);
|
2022-09-28 14:51:15 +00:00
|
|
|
vertexData.data.clear();
|
|
|
|
cubes.clear();
|
2022-09-27 17:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2022-09-27 21:03:43 +00:00
|
|
|
// CHUNK CREATION, DELETION, AND RETREVAL
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
static std::map<std::pair<int32_t, int32_t>, Chunk*> chunks{};
|
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk* Chunk::newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) {
|
2022-09-26 15:03:27 +00:00
|
|
|
Chunk* chunk = new Chunk(gridX, gridZ, world_seed);
|
|
|
|
chunks[{gridX, gridZ}] = std::move(chunk);
|
|
|
|
return chunks[{gridX, gridZ}];
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-26 17:24:16 +00:00
|
|
|
Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) {
|
2022-09-30 04:25:12 +00:00
|
|
|
auto it = chunks.find({gridX, gridZ});
|
|
|
|
if(it != chunks.end()) {
|
|
|
|
return it->second;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-30 04:25:12 +00:00
|
|
|
return nullptr;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 21:03:43 +00:00
|
|
|
void Chunk::deleteChunk(int32_t gridX, int32_t gridZ) {
|
|
|
|
Chunk* chunk = getChunk(gridX, gridZ);
|
|
|
|
if(chunk == nullptr) return; // Chunk does not exist or is already deleted
|
|
|
|
delete chunk;
|
|
|
|
chunks.erase({gridX, gridZ});
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK TEXTURE AND BLOCK LOADING
|
|
|
|
//
|
2022-09-25 23:05:56 +00:00
|
|
|
|
2022-09-27 00:57:53 +00:00
|
|
|
static std::map<uint8_t, Block> blocks{};
|
|
|
|
static std::map<std::string, uint32_t> texturesIds{};
|
|
|
|
static std::vector<xe::Image*> textures{};
|
|
|
|
|
|
|
|
uint32_t getTexture(const std::string& filePath) {
|
2022-09-29 02:55:07 +00:00
|
|
|
if(!texturesIds.count(filePath)) {
|
|
|
|
xe::Image* image = xe::Image::createImage(filePath, false);
|
|
|
|
texturesIds[filePath] = static_cast<uint32_t>(textures.size());
|
|
|
|
textures.push_back(image);
|
|
|
|
}
|
2022-09-27 00:57:53 +00:00
|
|
|
return texturesIds[filePath];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<xe::Image*>& Chunk::getTextures() {
|
|
|
|
return textures;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 00:57:53 +00:00
|
|
|
void Chunk::load() {
|
|
|
|
blocks[DIRT] = {{getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(DIRT_TEXTURE)}};
|
|
|
|
blocks[GRASS] = {{getTexture(GRASS_TEXTURE), getTexture(GRASS_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(GRASS_TEXTURE), getTexture(GRASS_TEXTURE)}};
|
2022-09-29 03:20:37 +00:00
|
|
|
blocks[FULL_GRASS] = {{getTexture(GRASS_TOP_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(GRASS_TOP_TEXTURE), getTexture(GRASS_TOP_TEXTURE)}};
|
2022-09-29 02:55:07 +00:00
|
|
|
blocks[STONE] = {{getTexture(STONE_TEXTURE), getTexture(STONE_TEXTURE), getTexture(STONE_TEXTURE), getTexture(STONE_TEXTURE), getTexture(STONE_TEXTURE), getTexture(STONE_TEXTURE)}};
|
|
|
|
blocks[SNOW] = {{getTexture(SNOW_TEXTURE), getTexture(SNOW_TEXTURE), getTexture(SNOW_TEXTURE), getTexture(SNOW_TEXTURE), getTexture(SNOW_TEXTURE), getTexture(SNOW_TEXTURE)}};
|
|
|
|
blocks[SAND] = {{getTexture(SAND_TEXTURE), getTexture(SAND_TEXTURE), getTexture(SAND_TEXTURE), getTexture(SAND_TEXTURE), getTexture(SAND_TEXTURE), getTexture(SAND_TEXTURE)}};
|
|
|
|
blocks[WATER] = {{getTexture(WATER_TEXTURE), getTexture(WATER_TEXTURE), getTexture(WATER_TEXTURE), getTexture(WATER_TEXTURE), getTexture(WATER_TEXTURE), getTexture(WATER_TEXTURE)}};
|
2022-09-29 03:20:37 +00:00
|
|
|
blocks[SHRUB] = {{getTexture(SHRUB_TEXTURE), getTexture(SHRUB_TEXTURE), getTexture(SHRUB_TOP_TEXTURE), getTexture(DIRT_TEXTURE), getTexture(SHRUB_TEXTURE), getTexture(SHRUB_TEXTURE)}};
|
|
|
|
blocks[FULL_SHRUB] = {{getTexture(SHRUB_TOP_TEXTURE), getTexture(SHRUB_TOP_TEXTURE), getTexture(SHRUB_TOP_TEXTURE), getTexture(SHRUB_TOP_TEXTURE), getTexture(SHRUB_TOP_TEXTURE), getTexture(SHRUB_TOP_TEXTURE)}};
|
2022-09-27 00:57:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Chunk::unload() {
|
|
|
|
for(const auto &image: textures) {
|
2022-09-28 13:38:25 +00:00
|
|
|
xe::Image::deleteImage(image);
|
2022-09-27 00:57:53 +00:00
|
|
|
}
|
2022-09-26 15:03:27 +00:00
|
|
|
for(const auto &[key, chunk]: chunks) {
|
|
|
|
delete chunk;
|
|
|
|
}
|
|
|
|
chunks.clear();
|
2022-09-27 00:57:53 +00:00
|
|
|
textures.clear();
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK MESH CREATION FOR BOTH SYNC AND ASYNC
|
|
|
|
//
|
2022-09-26 15:03:27 +00:00
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
void Chunk::createMeshAsync(Chunk* c) {
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c == nullptr) return;
|
2022-09-27 17:35:49 +00:00
|
|
|
if(c->working) return;
|
2022-09-28 23:36:35 +00:00
|
|
|
c->working = true;
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c->worker.joinable())
|
|
|
|
c->worker.join();
|
2022-09-27 17:35:49 +00:00
|
|
|
c->worker = std::thread(createMesh, c);
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-30 04:25:12 +00:00
|
|
|
struct FMask {
|
|
|
|
int block;
|
|
|
|
int normal;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool CompareMask(FMask a, FMask b){
|
|
|
|
if(a.block == INVALID || b.block == INVALID) return false;
|
|
|
|
return a.block == b.block && a.normal == b.normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddVertex(xe::Model::Data& data, glm::vec3 Pos, glm::vec3 Nor, FMask Mask, glm::vec3 AxisMask, float Uv[2]) {
|
|
|
|
data.write<float>(Pos[0]);
|
|
|
|
data.write<float>(Pos[1]);
|
|
|
|
data.write<float>(Pos[2]);
|
|
|
|
data.write<float>(Nor[0]);
|
|
|
|
data.write<float>(Nor[1]);
|
|
|
|
data.write<float>(Nor[2]);
|
|
|
|
data.write<float>(Uv[0]);
|
|
|
|
data.write<float>(Uv[1]);
|
|
|
|
|
|
|
|
int i = AxisMask[1]*2+AxisMask[2]*4+(Mask.normal<0?1:0);
|
|
|
|
data.write<uint32_t>(blocks[Mask.block].textures[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreateQuad(xe::Model::Data& data, FMask Mask, glm::vec3 AxisMask, glm::vec3 V1, glm::vec3 V2, glm::vec3 V3, glm::vec3 V4, uint32_t width, uint32_t height) {
|
|
|
|
const auto Normal = glm::vec3(AxisMask) * glm::vec3(Mask.normal);
|
2022-09-30 05:01:52 +00:00
|
|
|
std::vector<glm::vec3> verticies = {V4, V2, V3, V1};
|
2022-09-30 04:25:12 +00:00
|
|
|
|
|
|
|
float uv[4][2];
|
|
|
|
|
2022-09-30 05:01:52 +00:00
|
|
|
uv[0][0] = height; uv[0][1] = width;
|
2022-09-30 04:25:12 +00:00
|
|
|
uv[1][0] = height; uv[1][1] = 0;
|
|
|
|
uv[2][0] = 0; uv[2][1] = width;
|
|
|
|
uv[3][0] = 0; uv[3][1] = 0;
|
|
|
|
|
2022-09-30 05:01:52 +00:00
|
|
|
AddVertex(data, verticies[0], Normal, Mask, AxisMask, uv[1]);
|
|
|
|
AddVertex(data, verticies[2 + Mask.normal], Normal, Mask, AxisMask, uv[2]);
|
|
|
|
AddVertex(data, verticies[2 - Mask.normal], Normal, Mask, AxisMask, uv[0]);
|
|
|
|
AddVertex(data, verticies[3], Normal, Mask, AxisMask, uv[2]);
|
|
|
|
AddVertex(data, verticies[1 - Mask.normal], Normal, Mask, AxisMask, uv[1]);
|
|
|
|
AddVertex(data, verticies[1 + Mask.normal], Normal, Mask, AxisMask, uv[3]);
|
2022-09-30 04:25:12 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
void Chunk::createMesh(Chunk* c) {
|
2022-09-27 21:03:43 +00:00
|
|
|
if(c == nullptr) return;
|
2022-09-28 23:36:35 +00:00
|
|
|
if(!isGenerated(c->gridX-1, c->gridZ) ||
|
|
|
|
!isGenerated(c->gridX+1, c->gridZ) ||
|
|
|
|
!isGenerated(c->gridX, c->gridZ-1) ||
|
|
|
|
!isGenerated(c->gridX, c->gridZ+1)) {
|
|
|
|
c->working = false;
|
|
|
|
return;
|
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
c->vertexData.data.clear();
|
2022-09-30 04:25:12 +00:00
|
|
|
for (int Axis = 0; Axis < 3; ++Axis) {
|
|
|
|
const int Axis1 = (Axis + 1) % 3;
|
|
|
|
const int Axis2 = (Axis + 2) % 3;
|
|
|
|
|
|
|
|
const int MainAxisLimit = Axis == 1 ? 256 : 16;
|
|
|
|
int Axis1Limit = Axis1 == 1 ? 256 : 16;
|
|
|
|
int Axis2Limit = Axis2 == 1 ? 256 : 16;
|
|
|
|
|
|
|
|
auto DeltaAxis1 = glm::vec3(0.f);
|
|
|
|
auto DeltaAxis2 = glm::vec3(0.f);
|
|
|
|
|
|
|
|
auto ChunkItr = glm::vec3(0.f);
|
|
|
|
auto AxisMask = glm::vec3(0.f);
|
|
|
|
|
|
|
|
AxisMask[Axis] = 1;
|
|
|
|
|
|
|
|
std::vector<FMask> Mask;
|
|
|
|
Mask.resize(Axis1Limit * Axis2Limit);
|
|
|
|
|
|
|
|
for (ChunkItr[Axis] = -1; ChunkItr[Axis] < MainAxisLimit;) {
|
|
|
|
int N = 0;
|
|
|
|
|
|
|
|
for (ChunkItr[Axis2] = 0; ChunkItr[Axis2] < Axis2Limit; ++ChunkItr[Axis2]) {
|
|
|
|
for (ChunkItr[Axis1] = 0; ChunkItr[Axis1] < Axis1Limit; ++ChunkItr[Axis1]) {
|
|
|
|
const auto CurrentBlock = c->getBlock(ChunkItr[0], ChunkItr[1], ChunkItr[2]);
|
|
|
|
const auto CompareBlock = c->getBlock(ChunkItr[0] + AxisMask[0], ChunkItr[1] + AxisMask[1] , ChunkItr[2] + AxisMask[2]);
|
|
|
|
|
|
|
|
const bool CurrentBlockOpaque = CurrentBlock != AIR;
|
|
|
|
const bool CompareBlockOpaque = CompareBlock != AIR;
|
|
|
|
|
|
|
|
if (CurrentBlockOpaque == CompareBlockOpaque) {
|
|
|
|
Mask[N++] = FMask { INVALID, 0 };
|
|
|
|
} else if (CurrentBlockOpaque) {
|
|
|
|
Mask[N++] = FMask { CurrentBlock, 1};
|
|
|
|
} else {
|
|
|
|
Mask[N++] = FMask { CompareBlock, -1};
|
|
|
|
}
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-30 04:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
++ChunkItr[Axis];
|
|
|
|
N = 0;
|
|
|
|
|
|
|
|
for (int j = 0; j < Axis2Limit; ++j) {
|
|
|
|
for (int i = 0; i < Axis1Limit;) {
|
|
|
|
if(Mask[N].normal != 0) {
|
|
|
|
const auto CurrentMask = Mask[N];
|
|
|
|
ChunkItr[Axis1] = i;
|
|
|
|
ChunkItr[Axis2] = j;
|
|
|
|
|
|
|
|
int width;
|
|
|
|
|
|
|
|
for(width = 1; i + width < Axis1Limit && CompareMask(Mask[N + width], CurrentMask); ++width) {}
|
|
|
|
|
|
|
|
int height;
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
for (height = 1; j + height < Axis2Limit; ++height) {
|
|
|
|
for(int k = 0; k < width; ++k) {
|
|
|
|
if(CompareMask(Mask[N + k + height * Axis1Limit], CurrentMask)) continue;
|
|
|
|
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(done) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeltaAxis1[Axis1] = width;
|
|
|
|
DeltaAxis2[Axis2] = height;
|
|
|
|
|
|
|
|
CreateQuad(c->vertexData, CurrentMask, AxisMask,
|
|
|
|
ChunkItr,
|
|
|
|
ChunkItr + DeltaAxis1,
|
|
|
|
ChunkItr + DeltaAxis2,
|
|
|
|
ChunkItr + DeltaAxis1 + DeltaAxis2,
|
|
|
|
height,
|
|
|
|
width
|
|
|
|
);
|
|
|
|
|
|
|
|
DeltaAxis1 = glm::vec3(0.f);
|
|
|
|
DeltaAxis2 = glm::vec3(0.f);
|
|
|
|
|
|
|
|
for (int l = 0; l < height; ++l) {
|
|
|
|
for(int k = 0; k < width; ++k) {
|
|
|
|
Mask[N + k + l * Axis1Limit] = FMask { INVALID, 0 };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i += width;
|
|
|
|
N += width;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
i++;
|
|
|
|
N++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-30 04:25:12 +00:00
|
|
|
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-28 23:36:35 +00:00
|
|
|
c->reload = true;
|
2022-09-27 17:35:49 +00:00
|
|
|
c->working = false;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-28 23:36:35 +00:00
|
|
|
//
|
|
|
|
// CHUNK GENERATION FOR BOTH SYNC AND ASYNC
|
|
|
|
//
|
|
|
|
|
|
|
|
void Chunk::generateAsync(Chunk* c) {
|
|
|
|
if(c == nullptr) return;
|
|
|
|
if(c->working) return;
|
|
|
|
c->working = true;
|
|
|
|
if(c->worker.joinable())
|
|
|
|
c->worker.join();
|
|
|
|
c->worker = std::thread(generate, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Chunk::generate(Chunk* c) {
|
|
|
|
c->cubes.resize(16*16*256);
|
|
|
|
|
|
|
|
const PerlinNoise perlin{c->world_seed};
|
|
|
|
|
|
|
|
for(int x = 0; x < 16; x++) {
|
|
|
|
for(int z = 0; z < 16; z++) {
|
2022-09-29 03:20:37 +00:00
|
|
|
double biome = perlin.octave2D_01((( x + c->gridX * 13) * 0.0005), ((z + c->gridZ * 13) * 0.0005), 4) * 2;
|
|
|
|
double continent = perlin.octave2D_01((( x + c->gridX * 16) * 0.001), ((z + c->gridZ * 16) * 0.001), 4) * 10 - 5;
|
2022-09-29 02:55:07 +00:00
|
|
|
double noise = perlin.octave2D_01((( x + c->gridX * 16) * 0.01), ((z + c->gridZ * 16) * 0.01), 4);
|
2022-09-29 03:20:37 +00:00
|
|
|
int height = noise * 40 + continent;
|
2022-09-29 02:55:07 +00:00
|
|
|
for(int y = 0; y < std::max(height, WATER_LEVEL); y++) {
|
|
|
|
int difference = y - WATER_LEVEL;
|
|
|
|
if (difference < 0) {
|
|
|
|
c->setBlock(x, y, z, WATER);
|
|
|
|
} else if(difference < 3) {
|
|
|
|
c->setBlock(x, y, z, SAND);
|
|
|
|
} else if(difference < 5) {
|
2022-09-28 23:36:35 +00:00
|
|
|
c->setBlock(x, y, z, DIRT);
|
2022-09-29 02:55:07 +00:00
|
|
|
} else if(difference < 6) {
|
2022-09-29 03:20:37 +00:00
|
|
|
c->setBlock(x, y, z, biome > 1 ? GRASS : SHRUB);
|
2022-09-29 02:55:07 +00:00
|
|
|
} else if(difference < 10) {
|
2022-09-29 03:20:37 +00:00
|
|
|
c->setBlock(x, y, z, biome > 1 ? FULL_GRASS : FULL_SHRUB);
|
2022-09-29 02:55:07 +00:00
|
|
|
} else if(difference < 16) {
|
|
|
|
c->setBlock(x, y, z, STONE);
|
|
|
|
} else if(difference < 18) {
|
|
|
|
c->setBlock(x, y, z, SNOW);
|
|
|
|
}
|
2022-09-28 23:36:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c->generated = true;
|
|
|
|
c->working = false;
|
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
//
|
|
|
|
// CHUNK GETTERS AND SETTORS
|
|
|
|
//
|
|
|
|
|
|
|
|
xe::Model* Chunk::getMesh() {
|
2022-09-28 23:36:35 +00:00
|
|
|
if(reload) {
|
2022-09-28 01:40:20 +00:00
|
|
|
if(chunkMesh != nullptr) {
|
|
|
|
xe::Model::deleteModel(chunkMesh);
|
|
|
|
chunkMesh = nullptr;
|
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
if(worker.joinable())
|
|
|
|
worker.join();
|
|
|
|
xe::Model::Builder builder{};
|
|
|
|
builder.vertexData = vertexData;
|
|
|
|
builder.vertexSize = 36;
|
2022-09-28 13:38:25 +00:00
|
|
|
chunkMesh = xe::Model::createModel(builder);
|
2022-09-28 23:36:35 +00:00
|
|
|
vertexData.data.clear();
|
|
|
|
reload = false;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
2022-09-27 17:35:49 +00:00
|
|
|
return chunkMesh;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
2022-09-27 17:35:49 +00:00
|
|
|
uint8_t Chunk::getBlock(int32_t x, int32_t y, int32_t z) {
|
|
|
|
if(y > 256) return AIR;
|
|
|
|
if(y < 0) return INVALID;
|
|
|
|
int chunkX = gridX;
|
|
|
|
int chunkZ = gridZ;
|
|
|
|
if(x < 0) {
|
|
|
|
chunkX--;
|
|
|
|
} else if(x > 15) {
|
|
|
|
chunkX++;
|
|
|
|
}
|
|
|
|
if(z < 0) {
|
|
|
|
chunkZ--;
|
|
|
|
} else if(z > 15) {
|
|
|
|
chunkZ++;
|
|
|
|
}
|
|
|
|
x = (x+16)%16;
|
|
|
|
z = (z+16)%16;
|
|
|
|
if(chunkX == gridX && chunkZ == gridZ) {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
return cubes[index];
|
|
|
|
} else {
|
|
|
|
Chunk* chunk = getChunk(chunkX, chunkZ);
|
|
|
|
if(chunk == NULL) {
|
|
|
|
return INVALID;
|
|
|
|
} else {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
return chunk->cubes[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Chunk::setBlock(int32_t x, int32_t y, int32_t z, uint8_t block) {
|
|
|
|
int index = x + (z * 16) + (y * 256);
|
|
|
|
cubes[index] = block;
|
|
|
|
}
|
|
|
|
|
2022-09-28 23:36:35 +00:00
|
|
|
bool Chunk::isGenerated(int32_t gridX, int32_t gridZ) {
|
|
|
|
Chunk* chunk = Chunk::getChunk(gridX, gridZ);
|
|
|
|
if(chunk == nullptr) return false;
|
|
|
|
return chunk->generated;
|
2022-09-25 23:05:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|