123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- #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<Chunk>() ),
- entities( new RCArray<Entity>() )
- {}
- 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<Block*, int> Dimension::zBlock( Vec3<int> 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<int>( x, y, location.z ) );
- }
- return 0;
- }
- Block* Dimension::zRealBlockInstance( Framework::Vec3<int> 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<int>( x, y, location.z ) );
- return c->zBlockAt( Vec3<int>( x, y, location.z ) );
- }
- return 0;
- }
- void Dimension::placeBlock( Framework::Vec3<int> location, Framework::Either<Block*, int> 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<int>( x, y, location.z ), block );
- else
- {
- c->putBlockAt( Vec3<int>( x, y, location.z ), 0 );
- c->putBlockTypeAt( Vec3<int>( 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<EntityType>::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<int> 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<float> pos, std::function<bool( Entity* )> 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++;
- }
- }
|