#include "Chunk.h" #include "Constants.h" #include "Game.h" Chunk::Chunk( Framework::Punkt location, Game *zGame, int dimensionId ) : ReferenceCounter(), zGame( zGame ), dimensionId( dimensionId ), location( location ) { blocks = new Block * [ CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT ]; Block *val = (Block *)AIR_BLOCK; std::uninitialized_fill_n( blocks, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT, val ); zNeighbours[ 0 ] = 0; zNeighbours[ 1 ] = 0; zNeighbours[ 2 ] = 0; zNeighbours[ 3 ] = 0; } Chunk::Chunk( Framework::Punkt location, Game *zGame, int dimensionId, Framework::StreamReader *zReader ) : Chunk( location, zGame, dimensionId ) { load( zReader ); } Chunk::~Chunk() { for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ ) { if( IS_BLOCK( blocks[ i ] ) ) blocks[ i ]->release(); } delete[] blocks; } Block *Chunk::zBlockNeighbor( Framework::Vec3 location ) { if( location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0 && location.y < CHUNK_SIZE && location.z >= 0 && location.z < WORLD_HEIGHT ) return blocks[ (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z ]; if( location.z >= 0 && location.z < WORLD_HEIGHT ) return zGame->zBlockAt( { location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId ); return 0; } void Chunk::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse ) { // TODO: answer api messages } Block *Chunk::getBlockAt( Framework::Vec3 location ) const { assert( (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT ); Block *result = zBlockAt( location ); if( result ) return dynamic_cast(result->getThis()); return 0; } Block *Chunk::zBlockAt( Framework::Vec3 location ) const { assert( (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT ); return blocks[ (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z ]; } void Chunk::putBlockAt( Framework::Vec3 location, Block *block ) { int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z; assert( index < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT ); Block *old = blocks[ index ]; blocks[ index ] = block; Block *neighbor = zBlockNeighbor( location + getDirection( NORTH ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( SOUTH, block ); if( IS_BLOCK( block ) ) block->setNeighbour( NORTH, neighbor ); neighbor = zBlockNeighbor( location + getDirection( EAST ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( WEST, block ); if( IS_BLOCK( block ) ) block->setNeighbour( EAST, neighbor ); neighbor = zBlockNeighbor( location + getDirection( SOUTH ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( NORTH, block ); if( IS_BLOCK( block ) ) block->setNeighbour( SOUTH, neighbor ); neighbor = zBlockNeighbor( location + getDirection( WEST ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( EAST, block ); if( IS_BLOCK( block ) ) block->setNeighbour( WEST, neighbor ); neighbor = zBlockNeighbor( location + getDirection( TOP ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( BOTTOM, block ); if( IS_BLOCK( block ) ) block->setNeighbour( TOP, neighbor ); neighbor = zBlockNeighbor( location + getDirection( BOTTOM ) ); if( IS_BLOCK( neighbor ) ) neighbor->setNeighbour( TOP, block ); if( IS_BLOCK( block ) ) block->setNeighbour( BOTTOM, neighbor ); if( IS_BLOCK( old ) ) old->release(); } void Chunk::setNeighbor( Direction dir, Chunk *zChunk ) { zNeighbours[ getDirectionIndex(dir) ] = zChunk; for( int i = 0; i < CHUNK_SIZE; i++ ) { for( int z = 0; z < WORLD_HEIGHT; z++ ) { if( dir == NORTH ) { int index = i * CHUNK_SIZE * WORLD_HEIGHT + z; if( IS_BLOCK( blocks[ index ] ) ) blocks[ index ]->setNeighbour( NORTH, zChunk->blocks[ (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z ] ); } else if( dir == EAST ) { int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z; if( IS_BLOCK( blocks[ index ] ) ) blocks[ index ]->setNeighbour( EAST, zChunk->blocks[ i * WORLD_HEIGHT + z ] ); } else if( dir == SOUTH ) { int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z; if( IS_BLOCK( blocks[ index ] ) ) blocks[ index ]->setNeighbour( SOUTH, zChunk->blocks[ i * CHUNK_SIZE * WORLD_HEIGHT + z ] ); } else if( dir == WEST ) { int index = i * WORLD_HEIGHT + z; if( IS_BLOCK( blocks[ index ] ) ) blocks[ index ]->setNeighbour( WEST, zChunk->blocks[ ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z ] ); } } } } void Chunk::load( Framework::StreamReader *zReader ) { for( int x = 0; x < CHUNK_SIZE; x++ ) { for( int y = 0; y < CHUNK_SIZE; y++ ) { for( int z = 0; z < WORLD_HEIGHT; z++ ) { int blockType; zReader->lese( (char *)&blockType, 4 ); if( blockType >= 0 ) { Block *block = StaticRegistry::INSTANCE.zElement( blockType )->loadBlock( Framework::Vec3( x, y, z ), zGame, zReader ); putBlockAt( { x, y, z }, block ); } } } } } void Chunk::save( Framework::StreamWriter *zWriter ) { for( int x = 0; x < CHUNK_SIZE; x++ ) { for( int y = 0; y < CHUNK_SIZE; y++ ) { for( int z = 0; z < WORLD_HEIGHT; z++ ) { int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z; int blockType = IS_BLOCK(blocks[ index ]) ? blocks[ index ]->zBlockType()->getId() : -1; zWriter->schreibe( (char *)&blockType, 4 ); if( blockType >= 0 ) StaticRegistry::INSTANCE.zElement( blockType )->saveBlock( blocks[ index ], zWriter ); } } } } void Chunk::removeUnusedBlocks() { bool removed = true; while( removed ) { removed = false; for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ ) { if( IS_BLOCK( blocks[ i ] ) && !blocks[ i ]->isVisible() ) { int x = (i / WORLD_HEIGHT) / CHUNK_SIZE; int y = (i / WORLD_HEIGHT) % CHUNK_SIZE; int z = i % WORLD_HEIGHT; putBlockAt( { x,y,z }, 0 ); removed = true; } } } } int Chunk::getDimensionId() const { return dimensionId; } 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 }; } Game *Chunk::zGameObj() const { return zGame; }