#include "Chunk.h" #include "Constants.h" #include "DX12ChunkData.h" #include "Globals.h" Chunk::Chunk(Framework::Point location) : ReferenceCounter(), location(location), isLoading(0), lightChanged(0), bLock(), vLock(), aLock(), dx12Data(new DX12ChunkData(location)) { blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT]; memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*)); } Chunk::Chunk(Framework::Point location, Framework::StreamReader* zReader) : Chunk(location) { load(zReader); // for (ChunkModelBuilder* builder : modelBuilders) //{ // buildModel(builder); // } } Chunk::~Chunk() { char msg = 1; // remove observer if (World::INSTANCE) { World::INSTANCE->zClient()->chunkAPIRequest(location, &msg, 1); } bLock.lockWrite(); for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } delete[] blocks; bLock.unlockWrite(); dx12Data->release(); } void Chunk::appendAnimation( Block* zB, int boneId, double time, Vec3 pos, Vec3 rot) { if (!zB->zSkeleton() || !zB->zSkeleton()->zBone(boneId)) return; aLock.lockRead(); for (BlockAnimation* animation : animations) { if (animation->zBlock() == zB) { animation->appendAnimation(boneId, time, pos, rot); aLock.unlockRead(); return; } } aLock.unlockRead(); SkeletonAnimation* sa = new SkeletonAnimation(); Bone* bone = zB->zSkeleton()->zBone(boneId); sa->addAnimation(boneId, bone->getPosition(), bone->getRotation()); sa->addKeyFrame(boneId, time, pos, rot); aLock.lockWrite(); animations.add(new BlockAnimation(dynamic_cast(zB->getThis()), sa)); aLock.unlockWrite(); } void Chunk::load(Framework::StreamReader* zReader) { bLock.lockWrite(); for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } bLock.unlockWrite(); isLoading = 1; Framework::Vec3 pos = {0, 0, 0}; unsigned short id; zReader->read((char*)&id, 2); int count = 0; while (id) { int index; zReader->read((char*)&index, 4); char state = 0; zReader->read(&state, 1); char flowOptions = 0; char distanceToSource = 0; if (state & 1) { zReader->read(&flowOptions, 1); zReader->read(&distanceToSource, 1); } bool passable = 0; float speedModifier = 1.f; if (state & 2) { passable = 1; zReader->read((char*)&speedModifier, 4); } pos = Vec3((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); Direction dir = blockTypes[id]->getDefaultFrontDirection(); if (state & 4) { zReader->read((char*)&dir, 1); } if (blockTypes[id]->doesNeedInstance()) { Block* b = blockTypes[id]->createBlock( {pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z}, passable, speedModifier, dir); b->setFlow(flowOptions, distanceToSource); bLock.lockWrite(); blocks[index] = b; bLock.unlockWrite(); if (b->isVisible()) { if (blockTypes[id]->getModelInfo().getModelName().isEqual( "cube")) { dx12Data->setBlock(index, b); } else { vLock.lockWrite(); visibleBlocks.add(b); vLock.unlockWrite(); } } count++; } zReader->read((char*)&id, 2); } std::cout << "Loaded " << count << " blocks\n"; int index = 0; // light zReader->read((char*)&index, 4); char lightData[6]; while (index >= -1) { if (index == -1) { int x = 0; int y = 0; int z = 0; zReader->read((char*)&x, 4); zReader->read((char*)&y, 4); zReader->read((char*)&z, 4); zReader->read(lightData, 6); if (x == -1) { int cacheIndex = y * WORLD_HEIGHT + z; bLock.lockRead(); Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(WEST, (unsigned char*)lightData, 0); } bLock.unlockRead(); } else if (y == -1) { int cacheIndex = (x * CHUNK_SIZE) * WORLD_HEIGHT + z; bLock.lockRead(); Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(NORTH, (unsigned char*)lightData, 0); } bLock.unlockRead(); } else if (x == CHUNK_SIZE) { int cacheIndex = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y) * WORLD_HEIGHT + z; bLock.lockRead(); Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(EAST, (unsigned char*)lightData, 0); } bLock.unlockRead(); } else if (y == CHUNK_SIZE) { int cacheIndex = (x * CHUNK_SIZE + (CHUNK_SIZE - 1)) * WORLD_HEIGHT + z; bLock.lockRead(); Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(SOUTH, (unsigned char*)lightData, 0); } bLock.unlockRead(); } } else { zReader->read(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) { int cacheIndex = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; bLock.lockRead(); Block* zB = blocks[cacheIndex]; if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData, 0); if (zB->isVisible() && !visible) { zB->tick(0); vLock.lockWrite(); visibleBlocks.add(zB); vLock.unlockWrite(); } } bLock.unlockRead(); } else { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; World::INSTANCE->getChunkReadLock().lock(); Chunk* c = World::INSTANCE->zChunk( World::INSTANCE->getChunkCenter(pos.x, pos.y)); if (c) { c->getBlockReadLock().lock(); Block* zB = c->zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData(getOppositeDirection( getDirectionFromIndex(i)), (unsigned char*)lightData, c); if (zB->isVisible() && !visible) { zB->tick(0); vLock.lockWrite(); c->visibleBlocks.add(zB); vLock.unlockWrite(); } } c->getBlockReadLock().unlock(); } World::INSTANCE->getChunkReadLock().unlock(); } } } } zReader->read((char*)&index, 4); } isLoading = 0; } void Chunk::forAll(std::function f) { vLock.lockRead(); for (Block* b : visibleBlocks) { f(b); } vLock.unlockRead(); } bool Chunk::tick(std::function f, double time) { bool res = 0; aLock.lockRead(); auto iterator = animations.begin(); while (iterator) { if (iterator->tick(time)) { res |= iterator->zBlock()->tick(time); if (iterator->isFinished()) { aLock.lockWrite(); iterator.remove(); aLock.unlockWrite(); continue; } } else { aLock.lockWrite(); iterator.remove(); aLock.unlockWrite(); continue; } ++iterator; } aLock.unlockRead(); vLock.lockRead(); for (Block* b : visibleBlocks) { res |= b->tick(time); } vLock.unlockRead(); return 1; } void Chunk::destroy() {} void Chunk::api(char* message) { switch (message[0]) { case 0: // set block { unsigned short id = *(int*)(message + 1); int index = *(int*)(message + 3); char state = message[7]; char flowOptions = 0; char distanceToSource = 0; int i = 8; if (state & 1) { flowOptions = message[i++]; distanceToSource = message[i++]; } bool passable = 0; float speedModifier = 1.f; if (state & 2) { passable = 1; speedModifier = *(float*)(message + i); i += 4; } Direction dir = blockTypes[id]->getDefaultFrontDirection(); if (state & 4) { dir = (Direction)message[i++]; } 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, passable, speedModifier, dir); zB->setFlow(flowOptions, distanceToSource); setBlock(zB); } else { bLock.lockRead(); Block* zB = zBlockAt(location); if (zB) removeBlock(zB); bLock.unlockRead(); } break; } case 1: // animate block { int index = *(int*)(message + 1); int boneId = *(int*)(message + 5); double time = *(double*)(message + 9); Framework::Vec3 pos; pos.x = *(float*)(message + 17); pos.y = *(float*)(message + 21); pos.z = *(float*)(message + 25); Framework::Vec3 rot; rot.x = *(float*)(message + 29); rot.y = *(float*)(message + 33); rot.z = *(float*)(message + 37); 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; bLock.lockRead(); Block* zB = zBlockAt(location); if (zB) appendAnimation(zB, boneId, time, pos, rot); bLock.unlockRead(); break; } } } Block* Chunk::zBlockAt(Framework::Vec3 location) { if (location.z < 0 || location.z >= WORLD_HEIGHT) return 0; location.x = location.x % CHUNK_SIZE; location.y = location.y % CHUNK_SIZE; if (location.x < 0) location.x += CHUNK_SIZE; if (location.y < 0) location.y += CHUNK_SIZE; int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z; return blocks[index]; } void Chunk::setBlock(Block* block) { Framework::Vec3 pos = block->getLocation(); pos.x = pos.x % CHUNK_SIZE; pos.y = pos.y % CHUNK_SIZE; if (pos.x < 0) pos.x += CHUNK_SIZE; if (pos.y < 0) pos.y += CHUNK_SIZE; int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; bLock.lockWrite(); if (blocks[index]) { if (!blocks[index]->zBlockType()->getModelInfo().getModelName().isEqual( "cube")) { vLock.lockWrite(); for (Framework::ArrayIterator vi = visibleBlocks.begin(); vi; vi++) { if (blocks[index] == (Block*)vi) { vi.remove(); break; } } vLock.unlockWrite(); } blocks[index]->copyLightTo(block); blocks[index]->release(); } blocks[index] = block; bLock.unlockWrite(); if (block && block->isVisible()) { if (block->zBlockType()->getModelInfo().getModelName().isEqual("cube")) { dx12Data->setBlock(index, block); } else { dx12Data->setBlock(index, 0); vLock.lockWrite(); visibleBlocks.add(block); vLock.unlockWrite(); } } else { dx12Data->setBlock(index, 0); } } void Chunk::removeBlock(Block* zBlock) { if (!zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube")) { vLock.lockWrite(); for (Framework::ArrayIterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zBlock == (Block*)iterator) { iterator.remove(); break; } } vLock.unlockWrite(); } Vec3 pos = zBlock->getLocation(); pos.x = pos.x % CHUNK_SIZE; pos.y = pos.y % CHUNK_SIZE; if (pos.x < 0) pos.x += CHUNK_SIZE; if (pos.y < 0) pos.y += CHUNK_SIZE; int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; if (zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube")) { dx12Data->setBlock(index, 0); } bLock.lockWrite(); if (blocks[index]) { blocks[index]->release(); blocks[index] = 0; } bLock.unlockWrite(); } void Chunk::blockVisibilityChanged(Block* zB) { if (zB->isVisible()) { zB->tick(0); vLock.lockWrite(); visibleBlocks.add(zB); vLock.unlockWrite(); } else { vLock.lockWrite(); for (Framework::ArrayIterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zB == (Block*)iterator) { iterator.remove(); break; } } vLock.unlockWrite(); } } Framework::Point 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::setLightChanged(int type) { lightChanged |= type; } Lock& Chunk::getBlockReadLock() const { return bLock.getReadLock(); } DX12ChunkData* Chunk::zDX12Data() const { return dx12Data; }