#include "Dimension.h" #include "Constants.h" #include "Datei.h" #include "Game.h" using namespace Framework; Dimension::Dimension( int id ) : dimensionId( id ), gravity( 9.8f ), chunks( new Trie() ), entities( new RCArray() ) {} Dimension::~Dimension() { entities->release(); chunks->release(); } void Dimension::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse ) { // TODO: switch type chunck, block, entity } void Dimension::tickEntities() { for( auto entity : *entities ) { if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) ) entity->prepareTick( this ); } int index = 0; for( auto entity : *entities ) { if( !entity->isRemoved() && zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) ) entity->tick( this ); index++; } } void Dimension::getAddrOf( Punkt cPos, char* addr ) const { *(int*)addr = cPos.x; *((int*)addr + 1) = cPos.y; } void Dimension::getAddrOfWorld( Punkt wPos, char* addr ) const { if( wPos.x < 0 ) wPos.x -= CHUNK_SIZE; if( wPos.y < 0 ) // needed because otherwise would (-8, -8) have the same adress as (8, 8) wPos.y -= CHUNK_SIZE; wPos /= CHUNK_SIZE; getAddrOf( wPos, addr ); } Chunk* Dimension::zChunk( Punkt wPos ) const { char addr[ 8 ]; getAddrOfWorld( wPos, addr ); return chunks->z( addr, 8 ); } Framework::Either Dimension::zBlock( Vec3 location ) { Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) ); if( c ) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if( x < 0 ) x += CHUNK_SIZE; if( y < 0 ) y += CHUNK_SIZE; return c->zBlockAt( Vec3( x, y, location.z ) ); } return 0; } Block* Dimension::zRealBlockInstance( Framework::Vec3 location ) { Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) ); if( c ) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if( x < 0 ) x += CHUNK_SIZE; if( y < 0 ) y += CHUNK_SIZE; c->instantiateBlock( Vec3( x, y, location.z ) ); return c->zBlockAt( Vec3( x, y, location.z ) ); } return 0; } void Dimension::placeBlock( Framework::Vec3 location, Framework::Either block ) { Chunk* c = zChunk( Game::getChunkCenter( location.x, location.y ) ); if( c ) { int x = location.x % CHUNK_SIZE; int y = location.y % CHUNK_SIZE; if( x < 0 ) x += CHUNK_SIZE; if( y < 0 ) y += CHUNK_SIZE; if( block.isA() ) c->putBlockAt( Vec3( x, y, location.z ), block ); else { c->putBlockAt( Vec3( x, y, location.z ), 0 ); c->putBlockTypeAt( Vec3( x, y, location.z ), block ); } } else if( block.isA() ) block.getA()->release(); } void Dimension::addEntity( Entity* entity ) { entities->add( entity ); } void Dimension::setChunk( Chunk* chunk, Punkt center ) { char addr[ 8 ]; getAddrOfWorld( center, addr ); Chunk* old = chunks->z( addr, 8 ); if( old ) { for( int i = 0; i < chunkList.getEintragAnzahl(); i++ ) { if( chunkList.get( i ) == old ) { chunkList.remove( i ); break; } } } chunks->set( addr, 8, chunk ); if( chunk ) { chunkList.add( chunk ); chunk->setAdded(); } getAddrOfWorld( center + Punkt( CHUNK_SIZE, 0 ), addr ); Chunk* zChunk = chunks->z( addr, 8 ); if( zChunk ) { zChunk->setNeighbor( WEST, chunk ); if( chunk ) chunk->setNeighbor( EAST, zChunk ); } getAddrOfWorld( center + Punkt( -CHUNK_SIZE, 0 ), addr ); zChunk = chunks->z( addr, 8 ); if( zChunk ) { zChunk->setNeighbor( EAST, chunk ); if( chunk ) chunk->setNeighbor( WEST, zChunk ); } getAddrOfWorld( center + Punkt( 0, CHUNK_SIZE ), addr ); zChunk = chunks->z( addr, 8 ); if( zChunk ) { zChunk->setNeighbor( NORTH, chunk ); if( chunk ) chunk->setNeighbor( SOUTH, zChunk ); } getAddrOfWorld( center + Punkt( 0, -CHUNK_SIZE ), addr ); zChunk = chunks->z( addr, 8 ); if( zChunk ) { zChunk->setNeighbor( SOUTH, chunk ); if( chunk ) chunk->setNeighbor( NORTH, zChunk ); } } void Dimension::save( Text worldDir ) const { for( auto chunk = chunks->getIterator(); chunk; chunk++ ) { if( !chunk._ ) continue; Datei* file = new Datei(); Text filePath = worldDir + "/dim/" + dimensionId + "/"; filePath.appendHex( chunk->getCenter().x ); filePath += "_"; filePath.appendHex( chunk->getCenter().y ); filePath += ".chunk"; file->setDatei( filePath ); if( file->open( Datei::Style::schreiben ) ) chunk->save( file, StreamTarget::FULL ); file->close(); file->release(); } Text filePath = worldDir + "/dim/" + dimensionId + "/entities"; Datei* file = new Datei(); file->setDatei( filePath ); if( file->open( Datei::Style::schreiben ) ) { for( Entity* entity : *entities ) { if( entity->zType()->getId() != PlayerEntityType::ID ) { if( !entity->isRemoved() ) { int type = entity->zType()->getId(); file->schreibe( (char*)&type, 4 ); StaticRegistry::INSTANCE.zElement( type )->saveEntity( entity, file ); } } else { Datei pFile; pFile.setDatei( worldDir + "/player/" + ((Player*)entity)->getName() ); if( pFile.open( Datei::Style::schreiben ) ) PlayerEntityType::INSTANCE->saveEntity( entity, &pFile ); } } file->close(); } } int Dimension::getDimensionId() const { return dimensionId; } bool Dimension::hasChunck( int x, int y ) const { return zChunk( Punkt( x, y ) ); } float Dimension::getGravity() const { return gravity; } void Dimension::removeOldChunks() { Array removed; int index = 0; for( Chunk* chunk : chunkList ) { if( !chunk->hasViews() ) removed.add( index, 0 ); index++; } for( int i : removed ) { Chunk* chunk = chunkList.get( i ); // TODO: save chunk chunk->prepareRemove(); setChunk( 0, chunk->getCenter() ); } } Entity* Dimension::zEntity( int id ) { for( auto entity : *entities ) { if( !entity->isRemoved() && entity->getId() == id ) return entity; } return 0; } Entity* Dimension::zNearestEntity( Framework::Vec3 pos, std::function filter ) { Entity* result = 0; float sqDist = 0; for( auto entity : *entities ) { if( !entity->isRemoved() && filter( entity ) ) { float d = pos.abstandSq( entity->getPosition() ); if( !result || d < sqDist ) { result = entity; sqDist = d; } } } return result; } void Dimension::removeEntity( int id ) { int index = 0; for( auto entity : *entities ) { if( entity->getId() == id ) { entities->remove( index ); return; } index++; } }