Chunk.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include "Chunk.h"
  2. #include "Constants.h"
  3. #include "Game.h"
  4. Chunk::Chunk( Framework::Punkt location, Game *zGame, int dimensionId )
  5. : ReferenceCounter(),
  6. zGame( zGame ),
  7. dimensionId( dimensionId ),
  8. location( location )
  9. {
  10. blocks = new Block * [ CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT ];
  11. Block *val = (Block *)AIR_BLOCK;
  12. std::uninitialized_fill_n( blocks, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT, val );
  13. zNeighbours[ 0 ] = 0;
  14. zNeighbours[ 1 ] = 0;
  15. zNeighbours[ 2 ] = 0;
  16. zNeighbours[ 3 ] = 0;
  17. }
  18. Chunk::Chunk( Framework::Punkt location, Game *zGame, int dimensionId, Framework::StreamReader *zReader )
  19. : Chunk( location, zGame, dimensionId )
  20. {
  21. load( zReader );
  22. }
  23. Chunk::~Chunk()
  24. {
  25. for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ )
  26. {
  27. if( IS_BLOCK( blocks[ i ] ) )
  28. blocks[ i ]->release();
  29. }
  30. delete[] blocks;
  31. }
  32. Block *Chunk::zBlockNeighbor( Framework::Vec3<int> location )
  33. {
  34. if( location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0 && location.y < CHUNK_SIZE && location.z >= 0 && location.z < WORLD_HEIGHT )
  35. return blocks[ (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z ];
  36. if( location.z >= 0 && location.z < WORLD_HEIGHT )
  37. return zGame->zBlockAt( { location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId );
  38. return 0;
  39. }
  40. void Chunk::api( Framework::StreamReader *zRequest, NetworkResponse *zResponse )
  41. {
  42. // TODO: answer api messages
  43. }
  44. Block *Chunk::getBlockAt( Framework::Vec3<int> location ) const
  45. {
  46. assert( (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT );
  47. Block *result = zBlockAt( location );
  48. if( result )
  49. return dynamic_cast<Block *>(result->getThis());
  50. return 0;
  51. }
  52. Block *Chunk::zBlockAt( Framework::Vec3<int> location ) const
  53. {
  54. assert( (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT );
  55. return blocks[ (location.x * CHUNK_SIZE + location.y) * CHUNK_SIZE + location.z ];
  56. }
  57. void Chunk::putBlockAt( Framework::Vec3<int> location, Block *block )
  58. {
  59. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  60. assert( index < CHUNK_SIZE *CHUNK_SIZE *WORLD_HEIGHT );
  61. Block *old = blocks[ index ];
  62. blocks[ index ] = block;
  63. Block *neighbor = zBlockNeighbor( location + getDirection( NORTH ) );
  64. if( IS_BLOCK( neighbor ) )
  65. neighbor->setNeighbour( SOUTH, block );
  66. if( IS_BLOCK( block ) )
  67. block->setNeighbour( NORTH, neighbor );
  68. neighbor = zBlockNeighbor( location + getDirection( EAST ) );
  69. if( IS_BLOCK( neighbor ) )
  70. neighbor->setNeighbour( WEST, block );
  71. if( IS_BLOCK( block ) )
  72. block->setNeighbour( EAST, neighbor );
  73. neighbor = zBlockNeighbor( location + getDirection( SOUTH ) );
  74. if( IS_BLOCK( neighbor ) )
  75. neighbor->setNeighbour( NORTH, block );
  76. if( IS_BLOCK( block ) )
  77. block->setNeighbour( SOUTH, neighbor );
  78. neighbor = zBlockNeighbor( location + getDirection( WEST ) );
  79. if( IS_BLOCK( neighbor ) )
  80. neighbor->setNeighbour( EAST, block );
  81. if( IS_BLOCK( block ) )
  82. block->setNeighbour( WEST, neighbor );
  83. neighbor = zBlockNeighbor( location + getDirection( TOP ) );
  84. if( IS_BLOCK( neighbor ) )
  85. neighbor->setNeighbour( BOTTOM, block );
  86. if( IS_BLOCK( block ) )
  87. block->setNeighbour( TOP, neighbor );
  88. neighbor = zBlockNeighbor( location + getDirection( BOTTOM ) );
  89. if( IS_BLOCK( neighbor ) )
  90. neighbor->setNeighbour( TOP, block );
  91. if( IS_BLOCK( block ) )
  92. block->setNeighbour( BOTTOM, neighbor );
  93. if( IS_BLOCK( old ) )
  94. old->release();
  95. }
  96. void Chunk::setNeighbor( Direction dir, Chunk *zChunk )
  97. {
  98. zNeighbours[ getDirectionIndex(dir) ] = zChunk;
  99. for( int i = 0; i < CHUNK_SIZE; i++ )
  100. {
  101. for( int z = 0; z < WORLD_HEIGHT; z++ )
  102. {
  103. if( dir == NORTH )
  104. {
  105. int index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  106. if( IS_BLOCK( blocks[ index ] ) )
  107. blocks[ index ]->setNeighbour( NORTH, zChunk->blocks[ (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z ] );
  108. }
  109. else if( dir == EAST )
  110. {
  111. int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  112. if( IS_BLOCK( blocks[ index ] ) )
  113. blocks[ index ]->setNeighbour( EAST, zChunk->blocks[ i * WORLD_HEIGHT + z ] );
  114. }
  115. else if( dir == SOUTH )
  116. {
  117. int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  118. if( IS_BLOCK( blocks[ index ] ) )
  119. blocks[ index ]->setNeighbour( SOUTH, zChunk->blocks[ i * CHUNK_SIZE * WORLD_HEIGHT + z ] );
  120. }
  121. else if( dir == WEST )
  122. {
  123. int index = i * WORLD_HEIGHT + z;
  124. if( IS_BLOCK( blocks[ index ] ) )
  125. blocks[ index ]->setNeighbour( WEST, zChunk->blocks[ ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z ] );
  126. }
  127. }
  128. }
  129. }
  130. void Chunk::load( Framework::StreamReader *zReader )
  131. {
  132. for( int x = 0; x < CHUNK_SIZE; x++ )
  133. {
  134. for( int y = 0; y < CHUNK_SIZE; y++ )
  135. {
  136. for( int z = 0; z < WORLD_HEIGHT; z++ )
  137. {
  138. int blockType;
  139. zReader->lese( (char *)&blockType, 4 );
  140. if( blockType >= 0 )
  141. {
  142. Block *block = StaticRegistry<BlockType>::INSTANCE.zElement( blockType )->loadBlock( Framework::Vec3<int>( x, y, z ), zGame, zReader );
  143. putBlockAt( { x, y, z }, block );
  144. }
  145. }
  146. }
  147. }
  148. }
  149. void Chunk::save( Framework::StreamWriter *zWriter )
  150. {
  151. for( int x = 0; x < CHUNK_SIZE; x++ )
  152. {
  153. for( int y = 0; y < CHUNK_SIZE; y++ )
  154. {
  155. for( int z = 0; z < WORLD_HEIGHT; z++ )
  156. {
  157. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  158. int blockType = IS_BLOCK(blocks[ index ]) ? blocks[ index ]->zBlockType()->getId() : -1;
  159. zWriter->schreibe( (char *)&blockType, 4 );
  160. if( blockType >= 0 )
  161. StaticRegistry<BlockType>::INSTANCE.zElement( blockType )->saveBlock( blocks[ index ], zWriter );
  162. }
  163. }
  164. }
  165. }
  166. void Chunk::removeUnusedBlocks()
  167. {
  168. bool removed = true;
  169. while( removed )
  170. {
  171. removed = false;
  172. for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ )
  173. {
  174. if( IS_BLOCK( blocks[ i ] ) && !blocks[ i ]->isVisible() )
  175. {
  176. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  177. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  178. int z = i % WORLD_HEIGHT;
  179. putBlockAt( { x,y,z }, 0 );
  180. removed = true;
  181. }
  182. }
  183. }
  184. }
  185. int Chunk::getDimensionId() const
  186. {
  187. return dimensionId;
  188. }
  189. Framework::Punkt Chunk::getCenter() const
  190. {
  191. return location;
  192. }
  193. Framework::Vec3<int> Chunk::getMin() const
  194. {
  195. return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
  196. }
  197. Framework::Vec3<int> Chunk::getMax() const
  198. {
  199. return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
  200. }
  201. Game *Chunk::zGameObj() const
  202. {
  203. return zGame;
  204. }