Dimension.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include "Dimension.h"
  2. #include "Constants.h"
  3. #include "Datei.h"
  4. #include "Game.h"
  5. using namespace Framework;
  6. Dimension::Dimension( int id )
  7. : dimensionId( id ),
  8. gravity( 9.8f ),
  9. chunks( new Trie<Chunk>() ),
  10. entities( new RCArray<Entity>() )
  11. {}
  12. Dimension::~Dimension()
  13. {
  14. entities->release();
  15. chunks->release();
  16. }
  17. void Dimension::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse )
  18. {
  19. // TODO: switch type chunck, block, entity
  20. }
  21. void Dimension::tickEntities()
  22. {
  23. for( auto entity : *entities )
  24. {
  25. if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
  26. entity->prepareTick( this );
  27. }
  28. int index = 0;
  29. Array<int> removed;
  30. for( auto entity : *entities )
  31. {
  32. if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
  33. entity->tick( this );
  34. if( entity->isRemoved() )
  35. removed.add( index, 0 );
  36. index++;
  37. }
  38. for( int i : removed )
  39. entities->remove( i );
  40. }
  41. void Dimension::getAddrOf( Punkt cPos, char* addr ) const
  42. {
  43. *(int*)addr = cPos.x;
  44. *((int*)addr + 1) = cPos.y;
  45. }
  46. void Dimension::getAddrOfWorld( Punkt wPos, char* addr ) const
  47. {
  48. if( wPos.x < 0 )
  49. wPos.x -= CHUNK_SIZE;
  50. if( wPos.y < 0 ) // needed because otherwise would (-8, -8) have the same adress as (8, 8)
  51. wPos.y -= CHUNK_SIZE;
  52. wPos /= CHUNK_SIZE;
  53. getAddrOf( wPos, addr );
  54. }
  55. Chunk* Dimension::zChunk( Punkt wPos ) const
  56. {
  57. char addr[ 8 ];
  58. getAddrOfWorld( wPos, addr );
  59. return chunks->z( addr, 8 );
  60. }
  61. Framework::Either<Block*, int> Dimension::zBlock( Vec3<int> location )
  62. {
  63. Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) );
  64. if( c )
  65. {
  66. int x = location.x % CHUNK_SIZE;
  67. int y = location.y % CHUNK_SIZE;
  68. if( x < 0 )
  69. x += CHUNK_SIZE;
  70. if( y < 0 )
  71. y += CHUNK_SIZE;
  72. return c->zBlockAt( Vec3<int>( x, y, location.z ) );
  73. }
  74. return 0;
  75. }
  76. Block* Dimension::zRealBlockInstance( Framework::Vec3<int> location )
  77. {
  78. Chunk* c = zChunk( Game::INSTANCE->getChunkCenter( location.x, location.y ) );
  79. if( c )
  80. {
  81. int x = location.x % CHUNK_SIZE;
  82. int y = location.y % CHUNK_SIZE;
  83. if( x < 0 )
  84. x += CHUNK_SIZE;
  85. if( y < 0 )
  86. y += CHUNK_SIZE;
  87. c->instantiateBlock( Vec3<int>( x, y, location.z ) );
  88. return c->zBlockAt( Vec3<int>( x, y, location.z ) );
  89. }
  90. return 0;
  91. }
  92. void Dimension::placeBlock( Framework::Vec3<int> location, Framework::Either<Block*, int> block )
  93. {
  94. Chunk* c = zChunk( Game::getChunkCenter( location.x, location.y ) );
  95. if( c )
  96. {
  97. int x = location.x % CHUNK_SIZE;
  98. int y = location.y % CHUNK_SIZE;
  99. if( x < 0 )
  100. x += CHUNK_SIZE;
  101. if( y < 0 )
  102. y += CHUNK_SIZE;
  103. if( block.isA() )
  104. c->putBlockAt( location, block );
  105. else
  106. {
  107. c->putBlockAt( location, 0 );
  108. c->putBlockTypeAt( location, block );
  109. }
  110. }
  111. else if( block.isA() )
  112. block.getA()->release();
  113. }
  114. void Dimension::addEntity( Entity* entity )
  115. {
  116. entities->add( entity );
  117. }
  118. void Dimension::setChunk( Chunk* chunk, Punkt center )
  119. {
  120. char addr[ 8 ];
  121. getAddrOfWorld( center, addr );
  122. Chunk* old = chunks->z( addr, 8 );
  123. if( old )
  124. {
  125. for( int i = 0; i < chunkList.getEintragAnzahl(); i++ )
  126. {
  127. if( chunkList.get( i ) == old )
  128. {
  129. chunkList.remove( i );
  130. break;
  131. }
  132. }
  133. }
  134. chunks->set( addr, 8, chunk );
  135. if( chunk )
  136. {
  137. chunkList.add( chunk );
  138. chunk->setAdded();
  139. }
  140. getAddrOfWorld( center + Punkt( CHUNK_SIZE, 0 ), addr );
  141. Chunk* zChunk = chunks->z( addr, 8 );
  142. if( zChunk )
  143. {
  144. zChunk->setNeighbor( WEST, chunk );
  145. if( chunk )
  146. chunk->setNeighbor( EAST, zChunk );
  147. }
  148. getAddrOfWorld( center + Punkt( -CHUNK_SIZE, 0 ), addr );
  149. zChunk = chunks->z( addr, 8 );
  150. if( zChunk )
  151. {
  152. zChunk->setNeighbor( EAST, chunk );
  153. if( chunk )
  154. chunk->setNeighbor( WEST, zChunk );
  155. }
  156. getAddrOfWorld( center + Punkt( 0, CHUNK_SIZE ), addr );
  157. zChunk = chunks->z( addr, 8 );
  158. if( zChunk )
  159. {
  160. zChunk->setNeighbor( NORTH, chunk );
  161. if( chunk )
  162. chunk->setNeighbor( SOUTH, zChunk );
  163. }
  164. getAddrOfWorld( center + Punkt( 0, -CHUNK_SIZE ), addr );
  165. zChunk = chunks->z( addr, 8 );
  166. if( zChunk )
  167. {
  168. zChunk->setNeighbor( SOUTH, chunk );
  169. if( chunk )
  170. chunk->setNeighbor( NORTH, zChunk );
  171. }
  172. }
  173. void Dimension::save( Text worldDir ) const
  174. {
  175. for( auto chunk = chunks->getIterator(); chunk; chunk++ )
  176. {
  177. if( !chunk._ )
  178. continue;
  179. Datei* file = new Datei();
  180. Text filePath = worldDir + "/dim/" + dimensionId + "/";
  181. filePath.appendHex( chunk->getCenter().x );
  182. filePath += "_";
  183. filePath.appendHex( chunk->getCenter().y );
  184. filePath += ".chunk";
  185. file->setDatei( filePath );
  186. if( file->open( Datei::Style::schreiben ) )
  187. chunk->save( file, StreamTarget::FULL );
  188. file->close();
  189. file->release();
  190. }
  191. Text filePath = worldDir + "/dim/" + dimensionId + "/entities";
  192. Datei* file = new Datei();
  193. file->setDatei( filePath );
  194. if( file->open( Datei::Style::schreiben ) )
  195. {
  196. for( Entity* entity : *entities )
  197. {
  198. if( entity->zType()->getId() != PlayerEntityType::ID )
  199. {
  200. if( !entity->isRemoved() )
  201. {
  202. int type = entity->zType()->getId();
  203. file->schreibe( (char*)&type, 4 );
  204. StaticRegistry<EntityType>::INSTANCE.zElement( type )->saveEntity( entity, file );
  205. }
  206. }
  207. else
  208. {
  209. Datei pFile;
  210. pFile.setDatei( worldDir + "/player/" + ((Player*)entity)->getName() );
  211. if( pFile.open( Datei::Style::schreiben ) )
  212. PlayerEntityType::INSTANCE->saveEntity( entity, &pFile );
  213. }
  214. }
  215. file->close();
  216. }
  217. }
  218. int Dimension::getDimensionId() const
  219. {
  220. return dimensionId;
  221. }
  222. bool Dimension::hasChunck( int x, int y ) const
  223. {
  224. return zChunk( Punkt( x, y ) );
  225. }
  226. float Dimension::getGravity() const
  227. {
  228. return gravity;
  229. }
  230. void Dimension::removeOldChunks()
  231. {
  232. Array<int> removed;
  233. int index = 0;
  234. for( Chunk* chunk : chunkList )
  235. {
  236. if( !chunk->hasViews() )
  237. removed.add( index, 0 );
  238. index++;
  239. }
  240. for( int i : removed )
  241. {
  242. Chunk* chunk = chunkList.get( i );
  243. // TODO: save chunk
  244. chunk->prepareRemove();
  245. setChunk( 0, chunk->getCenter() );
  246. }
  247. }