#include "Chunk.h" #include #include "ChunkFluidModel.h" #include "ChunkGroundModel.h" #include "Constants.h" #include "CustomDX11API.h" #include "FactoryCraftModel.h" #include "Globals.h" #include "TransparentChunkGroundModel.h" Chunk::Chunk(Framework::Punkt location) : ReferenceCounter(), location(location), isLoading(0), lightChanged(0) { blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT]; memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*)); FactoryCraftModel* ground = new FactoryCraftModel(); Model3DData* chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel( Text("chunk_ground_") + location.x + location.y); if (!chunkModel) { chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->createModel( Text("chunk_ground_") + location.x + location.y); } chunkModel->setAmbientFactor(0.f); chunkModel->setDiffusFactor(1.f); chunkModel->setSpecularFactor(0.f); chunkModel->setVertecies(0, 0); ground->setModelDaten(chunkModel); ground->setPosition( (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f); ground->tick(0); ChunkModelBuilder* groundModel = new ChunkGroundModel(ground, this); modelBuilders.add(groundModel); FactoryCraftModel* transparentGround = new FactoryCraftModel(); chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel( Text("transparent_chunk_ground_") + location.x + location.y); if (!chunkModel) { chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->createModel( Text("transparent_chunk_ground_") + location.x + location.y); } chunkModel->setAmbientFactor(0.f); chunkModel->setDiffusFactor(1.f); chunkModel->setSpecularFactor(0.f); chunkModel->setVertecies(0, 0); transparentGround->setModelDaten(chunkModel); transparentGround->setPosition( (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f); transparentGround->tick(0); ChunkModelBuilder* transparentGroundModel = new TransparentChunkGroundModel(transparentGround, this); modelBuilders.add(transparentGroundModel); FactoryCraftModel* fluids = new FactoryCraftModel(); chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel( Text("chunk_fluids_") + location.x + location.y); if (!chunkModel) { chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->createModel( Text("chunk_fluids_") + location.x + location.y); } chunkModel->setAmbientFactor(0.f); chunkModel->setDiffusFactor(1.f); chunkModel->setSpecularFactor(0.f); chunkModel->setVertecies(0, 0); fluids->setModelDaten(chunkModel); fluids->setPosition( (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f); fluids->tick(0); ChunkModelBuilder* fluidModel = new ChunkFluidModel(fluids, this); modelBuilders.add(fluidModel); } Chunk::Chunk(Framework::Punkt 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); } for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } delete[] blocks; } void Chunk::appendAnimation( Block* zB, int boneId, double time, Vec3 pos, Vec3 rot) { if (!zB->zSkeleton() || !zB->zSkeleton()->zBone(boneId)) return; acs.lock(); for (BlockAnimation* animation : animations) { if (animation->zBlock() == zB) { animation->appendAnimation(boneId, time, pos, rot); acs.unlock(); return; } } SkeletonAnimation* sa = new SkeletonAnimation(); Bone* bone = zB->zSkeleton()->zBone(boneId); sa->addAnimation(boneId, bone->getPosition(), bone->getRotation()); sa->addKeyFrame(boneId, time, pos, rot); animations.add(new BlockAnimation(dynamic_cast(zB->getThis()), sa)); acs.unlock(); } void Chunk::load(Framework::StreamReader* zReader) { cs.lock(); for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } cs.unlock(); isLoading = 1; Framework::Vec3 pos = {0, 0, 0}; unsigned short id; zReader->lese((char*)&id, 2); int count = 0; while (id) { int index; zReader->lese((char*)&index, 4); char state = 0; zReader->lese(&state, 1); char flowOptions = 0; char distanceToSource = 0; if ((state | 1) == state) { zReader->lese(&flowOptions, 1); zReader->lese(&distanceToSource, 1); } bool passable = 0; float speedModifier = 1.f; if ((state | 2) == state) { passable = 1; zReader->lese((char*)&speedModifier, 4); } pos = Vec3((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); if (blockTypes[id]->doesNeedInstance()) { cs.lock(); Block* b = blockTypes[id]->createBlock( {pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z}, passable, speedModifier); b->setFlow(flowOptions, distanceToSource); blocks[index] = b; cs.unlock(); vcs.lock(); if (b->isVisible()) { if (!blockTypes[id]->getModelInfo().getModelName().istGleich( "cube") && !blockTypes[id]->getModelInfo().getModelName().istGleich( "grass")) { b->tick(0); visibleBlocks.add(b); } } count++; vcs.unlock(); } zReader->lese((char*)&id, 2); } std::cout << "Loaded " << count << " blocks\n"; int index = 0; // light zReader->lese((char*)&index, 4); char lightData[6]; while (index >= -1) { if (index == -1) { int x = 0; int y = 0; int z = 0; zReader->lese((char*)&x, 4); zReader->lese((char*)&y, 4); zReader->lese((char*)&z, 4); zReader->lese(lightData, 6); if (x == -1) { int cacheIndex = y * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(WEST, (unsigned char*)lightData, 0); } } else if (y == -1) { int cacheIndex = (x * CHUNK_SIZE) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(NORTH, (unsigned char*)lightData, 0); } } else if (x == CHUNK_SIZE) { int cacheIndex = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(EAST, (unsigned char*)lightData, 0); } } else if (y == CHUNK_SIZE) { int cacheIndex = (x * CHUNK_SIZE + (CHUNK_SIZE - 1)) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(SOUTH, (unsigned char*)lightData, 0); } } } else { 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) { int cacheIndex = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; Block* zB = blocks[cacheIndex]; if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData, 0); if (zB->isVisible() && !visible) { vcs.lock(); zB->tick(0); visibleBlocks.add(zB); vcs.unlock(); } } } else { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Chunk* c = World::INSTANCE->zChunk( World::INSTANCE->getChunkCenter(pos.x, pos.y)); Block* zB = c ? c->zBlockAt(pos) : 0; if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData, c); if (zB->isVisible() && !visible) { c->vcs.lock(); zB->tick(0); c->visibleBlocks.add(zB); c->vcs.unlock(); } } } } } } zReader->lese((char*)&index, 4); } isLoading = 0; } void Chunk::buildModel(ChunkModelBuilder* builder) { vcs.lock(); modelChanged &= ~builder->getType(); lightChanged &= ~builder->getType(); builder->buildModel(); vcs.unlock(); } void Chunk::updateLight(ChunkModelBuilder* builder) { vcs.lock(); lightChanged &= ~builder->getType(); builder->updateLightning(); vcs.unlock(); } void Chunk::renderSolid(std::function f) { vcs.lock(); CustomDX11API* api = (CustomDX11API*)uiFactory.initParam.bildschirm->zGraphicsApi(); api->setCullBack(false); for (ChunkModelBuilder* builder : modelBuilders) { if (!builder->isTransparent()) { f(builder->zModel()); } } api->setCullBack(true); float dist = 0.f; for (Block* b : visibleBlocks) { f(b); } vcs.unlock(); } void Chunk::renderTransparent(std::function f) { CustomDX11API* api = (CustomDX11API*)uiFactory.initParam.bildschirm->zGraphicsApi(); api->setCullBack(false); for (ChunkModelBuilder* builder : modelBuilders) { if (builder->isTransparent()) { f(builder->zModel()); } } api->setCullBack(true); } bool Chunk::tick(std::function f, double time) { acs.lock(); vcs.lock(); // TODO: enshure no dead lock occures for (ChunkModelBuilder* builder : modelBuilders) { if ((modelChanged | builder->getType()) == modelChanged) buildModel(builder); } for (ChunkModelBuilder* builder : modelBuilders) { if ((lightChanged | builder->getType()) == lightChanged) updateLight(builder); } bool res = 0; for (ChunkModelBuilder* builder : modelBuilders) { res |= builder->zModel()->tick(time); } auto iterator = animations.begin(); while (iterator) { if (iterator->tick(time)) { res |= iterator->zBlock()->tick(time); if (iterator->isFinished()) { iterator.remove(); continue; } } else { iterator.remove(); continue; } ++iterator; } vcs.unlock(); acs.unlock(); return 1; } void Chunk::destroy() { for (ChunkModelBuilder* builder : modelBuilders) { Model3DData* chunkModel = builder->zModel()->zModelData(); // remove old model while (chunkModel->getPolygonAnzahl() > 0) { chunkModel->removePolygon(0); } chunkModel->setVertecies(0, 0); } } 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; if ((state | 1) == state) { flowOptions = message[8]; distanceToSource = message[9]; } bool passable = 0; float speedModifier = 1.f; if ((state | 2) == state) { passable = 1; speedModifier = *(float*)(message + 10); } 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); zB->setFlow(flowOptions, distanceToSource); setBlock(zB); } else { Block* zB = zBlockAt(location); if (zB) removeBlock(zB); } 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* zB = zBlockAt(location); if (zB) appendAnimation(zB, boneId, time, pos, rot); 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) { cs.lock(); 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; int affectsGround = 0; int newAffectsGround = 0; for (ChunkModelBuilder* builder : modelBuilders) { if (block && builder->isPartOfModel(block)) { newAffectsGround |= builder->getType(); } if (blocks[index] && builder->isPartOfModel(blocks[index])) { affectsGround |= builder->getType(); } } if (blocks[index]) { vcs.lock(); for (Framework::ArrayIterator vi = visibleBlocks.begin(); vi; vi++) { if (blocks[index] == (Block*)vi) { vi.remove(); break; } } vcs.unlock(); blocks[index]->copyLightTo(block); blocks[index]->release(); blocks[index] = block; cs.unlock(); vcs.lock(); modelChanged |= affectsGround | newAffectsGround; if (block && block->isVisible() && !newAffectsGround) { block->tick(0); visibleBlocks.add(block); } vcs.unlock(); return; } blocks[index] = block; cs.unlock(); vcs.lock(); modelChanged |= affectsGround | newAffectsGround; if (block && block->isVisible() && !newAffectsGround) { block->tick(0); visibleBlocks.add(block); } vcs.unlock(); } void Chunk::removeBlock(Block* zBlock) { cs.lock(); vcs.lock(); for (Framework::ArrayIterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zBlock == (Block*)iterator) { iterator.remove(); break; } } vcs.unlock(); 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 (blocks[index]) { modelChanged |= blocks[index]->getPartOfModels(); blocks[index]->release(); blocks[index] = 0; } cs.unlock(); } void Chunk::blockVisibilityChanged(Block* zB) { vcs.lock(); if (zB->isVisible()) { zB->tick(0); visibleBlocks.add(zB); } else { for (Framework::ArrayIterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zB == (Block*)iterator) { iterator.remove(); break; } } } vcs.unlock(); } 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::setModelChanged(int type) { modelChanged |= type; } void Chunk::setLightChanged(int type) { lightChanged |= type; }