#include "Chunk.h" #include "Constants.h" #include "Globals.h" #include "Registries.h" Chunk::Chunk(Framework::Punkt location) : ReferenceCounter(), location(location), isLoading(0) {} Chunk::Chunk(Framework::Punkt location, Framework::StreamReader* zReader) : Chunk(location) { load(zReader); } Chunk::~Chunk() { char msg = 1; // remove observer World::INSTANCE->zClient()->chunkAPIRequest(location, &msg, 1); } void Chunk::api(char* message) { switch (message[0]) { case 0: // set block { int index = *(int*)(message + 1); int id = *(int*)(message + 5); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); location.x += this->location.x - CHUNK_SIZE / 2; location.y += this->location.y - CHUNK_SIZE / 2; if (blockTypes[id]->doesNeedInstance()) { Block* zB = blockTypes[id]->createBlock(location); setBlock(zB); } else { Block* zB = zBlockAt(location); if (zB) removeBlock(zB); } break; } case 1: // update light { int index = *(int*)(message + 1); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); for (int i = 0; i < 6; i++) { Framework::Vec3 pos = location + getDirection(getDirectionFromIndex(i)); if (pos.z >= 0 && pos.z < WORLD_HEIGHT) { if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0 && pos.y < CHUNK_SIZE) { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Block* zB = zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData(getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)(message + 5)); if (zB->isVisible() != visible) { vcs.lock(); if (zB->isVisible()) visibleBlocks.add(zB); else { for (Framework::Iterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zB == (Block*)iterator) { iterator.remove(); break; } } } vcs.unlock(); } } } else { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Block* zB = World::INSTANCE->zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData(getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)(message + 5)); if (zB->isVisible() != visible) { Chunk* c = World::INSTANCE->zChunk(World::INSTANCE->getChunkCenter(pos.x, pos.y)); c->vcs.lock(); if (zB->isVisible()) c->visibleBlocks.add(zB); else { for (Framework::Iterator iterator = c->visibleBlocks.begin(); iterator; iterator++) { if (zB == (Block*)iterator) { iterator.remove(); break; } } } c->vcs.unlock(); } } } } } } } } Block* Chunk::zBlockAt(Framework::Vec3 location) { cs.lock(); for (Block* b : blocks) { if (b->getLocation() == location) { cs.unlock(); return b; } } cs.unlock(); return 0; } void Chunk::setBlock(Block* block) { cs.lock(); Framework::Vec3 pos = block->getLocation(); for (Framework::Iterator iterator = blocks.begin(); iterator; iterator++) { if (pos == iterator->getLocation()) { vcs.lock(); for (Framework::Iterator vi = visibleBlocks.begin(); vi; vi++) { if ((Block*)iterator == (Block*)vi) { iterator.remove(); break; } } vcs.unlock(); iterator->release(); iterator.set(block); break; } } blocks.add(block); cs.unlock(); } void Chunk::removeBlock(Block* zBlock) { cs.lock(); vcs.lock(); for (Framework::Iterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zBlock == (Block*)iterator) { iterator.remove(); break; } } vcs.unlock(); for (Framework::Iterator iterator = blocks.begin(); iterator; iterator++) { if (zBlock == (Block*)iterator) { iterator.remove(); break; } } cs.unlock(); } void Chunk::load(Framework::StreamReader* zReader) { isLoading = 1; Framework::Vec3 pos = { 0, 0, 0 }; unsigned short id; zReader->lese((char*)&id, 2); while (id) { int index; zReader->lese((char*)&index, 4); pos = Vec3((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); if (blockTypes[id]->doesNeedInstance()) setBlock(blockTypes[id]->createBlock({ pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z })); zReader->lese((char*)&id, 2); } int index = 0; // light zReader->lese((char*)&index, 4); char lightData[6]; while (index >= 0) { zReader->lese(lightData, 6); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); for (int i = 0; i < 6; i++) { Framework::Vec3 pos = location + getDirection(getDirectionFromIndex(i)); if (pos.z >= 0 && pos.z < WORLD_HEIGHT) { if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0 && pos.y < CHUNK_SIZE) { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Block* zB = zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData(getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData); if (zB->isVisible() && !visible) visibleBlocks.add(zB); } } else { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Block* zB = World::INSTANCE->zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData(getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData); if (zB->isVisible() && !visible) { Chunk* c = World::INSTANCE->zChunk(World::INSTANCE->getChunkCenter(pos.x, pos.y)); c->vcs.lock(); c->visibleBlocks.add(zB); c->vcs.unlock(); } } } } } zReader->lese((char*)&index, 4); } isLoading = 0; } Framework::Punkt Chunk::getCenter() const { return location; } Framework::Vec3 Chunk::getMin() const { return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 }; } Framework::Vec3 Chunk::getMax() const { return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT }; } void Chunk::forAll(std::function f) { vcs.lock(); for (Block* b : visibleBlocks) f(b); vcs.unlock(); }