Chunk.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include "Chunk.h"
  2. #include "Constants.h"
  3. #include "Block.h"
  4. #include "Globals.h"
  5. #include "Registries.h"
  6. Chunk::Chunk( Framework::Punkt location, int dimensionId )
  7. : ReferenceCounter(),
  8. dimensionId( dimensionId ),
  9. location( location )
  10. {
  11. blocks = new Block * [ CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT ];
  12. blockIds = new unsigned short[ CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT ];
  13. memset( blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof( Block* ) );
  14. memset( blockIds, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof( unsigned short ) );
  15. zNeighbours[ 0 ] = 0;
  16. zNeighbours[ 1 ] = 0;
  17. zNeighbours[ 2 ] = 0;
  18. zNeighbours[ 3 ] = 0;
  19. }
  20. Chunk::Chunk( Framework::Punkt location, int dimensionId, Framework::StreamReader* zReader )
  21. : Chunk( location, dimensionId )
  22. {
  23. load( zReader );
  24. }
  25. Chunk::~Chunk()
  26. {
  27. for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ )
  28. {
  29. if( blocks[ i ] )
  30. blocks[ i ]->release();
  31. }
  32. delete[] blocks;
  33. delete[] blockIds;
  34. }
  35. Framework::Either<Block*, int> Chunk::zBlockNeighbor( Framework::Vec3<int> location )
  36. {
  37. if( location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0 && location.y < CHUNK_SIZE && location.z >= 0 && location.z < WORLD_HEIGHT )
  38. {
  39. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  40. if( blocks[ index ] )
  41. return blocks[ index ];
  42. else
  43. return (int)blockIds[ index ];
  44. }
  45. if( location.z >= 0 && location.z < WORLD_HEIGHT )
  46. return currentGame->zBlockAt( { location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId );
  47. return 0;
  48. }
  49. bool Chunk::updateVisibility()
  50. {
  51. bool update = false;
  52. for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ )
  53. {
  54. if( blocks[ i ] )
  55. update |= blocks[ i ]->updateVisibility();
  56. }
  57. return update;
  58. }
  59. Framework::Either<Block*, int> Chunk::zBlockAt( Framework::Vec3<int> location ) const
  60. {
  61. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  62. assert( index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT );
  63. if( blocks[ index ] )
  64. return blocks[ index ];
  65. else
  66. return (int)blockIds[ index ];
  67. }
  68. const Block* Chunk::zBlockConst( Framework::Vec3<int> location ) const
  69. {
  70. Block* b = zBlockAt( location );
  71. if( b )
  72. return b;
  73. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  74. if( blockIds[ index ] )
  75. return STATIC_REGISTRY( BlockType ).zElement( blockIds[ index ] )->zDefault();
  76. return 0;
  77. }
  78. void Chunk::putBlockAt( Framework::Vec3<int> location, Block* block )
  79. {
  80. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  81. assert( index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT );
  82. Block* old = blocks[ index ];
  83. if( block )
  84. blockIds[ index ] = (unsigned short)block->zBlockType()->getId();
  85. blocks[ index ] = block;
  86. Either<Block*, int> neighbor = zBlockNeighbor( location + getDirection( NORTH ) );
  87. if( neighbor.isA() )
  88. ((Block*)neighbor)->setNeighbour( SOUTH, block );
  89. if( block )
  90. block->setNeighbour( NORTH, neighbor );
  91. neighbor = zBlockNeighbor( location + getDirection( EAST ) );
  92. if( neighbor.isA() )
  93. ((Block*)neighbor)->setNeighbour( WEST, block );
  94. if( block )
  95. block->setNeighbour( EAST, neighbor );
  96. neighbor = zBlockNeighbor( location + getDirection( SOUTH ) );
  97. if( neighbor.isA() )
  98. ((Block*)neighbor)->setNeighbour( NORTH, block );
  99. if( block )
  100. block->setNeighbour( SOUTH, neighbor );
  101. neighbor = zBlockNeighbor( location + getDirection( WEST ) );
  102. if( neighbor.isA() )
  103. ((Block*)neighbor)->setNeighbour( EAST, block );
  104. if( block )
  105. block->setNeighbour( WEST, neighbor );
  106. neighbor = zBlockNeighbor( location + getDirection( TOP ) );
  107. if( neighbor.isA() )
  108. ((Block*)neighbor)->setNeighbour( BOTTOM, block );
  109. if( block )
  110. block->setNeighbour( TOP, neighbor );
  111. neighbor = zBlockNeighbor( location + getDirection( BOTTOM ) );
  112. if( neighbor.isA() )
  113. ((Block*)neighbor)->setNeighbour( TOP, block );
  114. if( block )
  115. block->setNeighbour( BOTTOM, neighbor );
  116. if( old )
  117. old->release();
  118. }
  119. void Chunk::putBlockTypeAt( Framework::Vec3<int> location, int type )
  120. {
  121. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  122. assert( index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT );
  123. blockIds[ index ] = (unsigned short)type;
  124. Either<Block*, int> neighbor = zBlockNeighbor( location + getDirection( NORTH ) );
  125. if( neighbor.isA() )
  126. ((Block*)neighbor)->setNeighbourType( SOUTH, type );
  127. neighbor = zBlockNeighbor( location + getDirection( EAST ) );
  128. if( neighbor.isA() )
  129. ((Block*)neighbor)->setNeighbourType( WEST, type );
  130. neighbor = zBlockNeighbor( location + getDirection( SOUTH ) );
  131. if( neighbor.isA() )
  132. ((Block*)neighbor)->setNeighbourType( NORTH, type );
  133. neighbor = zBlockNeighbor( location + getDirection( WEST ) );
  134. if( neighbor.isA() )
  135. ((Block*)neighbor)->setNeighbourType( EAST, type );
  136. neighbor = zBlockNeighbor( location + getDirection( TOP ) );
  137. if( neighbor.isA() )
  138. ((Block*)neighbor)->setNeighbourType( BOTTOM, type );
  139. neighbor = zBlockNeighbor( location + getDirection( BOTTOM ) );
  140. if( neighbor.isA() )
  141. ((Block*)neighbor)->setNeighbourType( TOP, type );
  142. }
  143. void Chunk::setNeighbor( Direction dir, Chunk* zChunk )
  144. {
  145. zNeighbours[ getDirectionIndex( dir ) ] = zChunk;
  146. for( int i = 0; i < CHUNK_SIZE; i++ )
  147. {
  148. for( int z = 0; z < WORLD_HEIGHT; z++ )
  149. {
  150. if( dir == NORTH )
  151. {
  152. int index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  153. if( blocks[ index ] )
  154. {
  155. int j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  156. if( zChunk->blocks[ j ] )
  157. blocks[ index ]->setNeighbour( NORTH, zChunk->blocks[ j ] );
  158. else
  159. blocks[ index ]->setNeighbourType( NORTH, zChunk->blockIds[ j ] );
  160. }
  161. }
  162. else if( dir == EAST )
  163. {
  164. int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  165. if( blocks[ index ] )
  166. blocks[ index ]->setNeighbour( EAST, zChunk->blocks[ i * WORLD_HEIGHT + z ] );
  167. }
  168. else if( dir == SOUTH )
  169. {
  170. int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  171. if( blocks[ index ] )
  172. blocks[ index ]->setNeighbour( SOUTH, zChunk->blocks[ i * CHUNK_SIZE * WORLD_HEIGHT + z ] );
  173. }
  174. else if( dir == WEST )
  175. {
  176. int index = i * WORLD_HEIGHT + z;
  177. if( blocks[ index ] )
  178. blocks[ index ]->setNeighbour( WEST, zChunk->blocks[ ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z ] );
  179. }
  180. }
  181. }
  182. }
  183. void Chunk::load( Framework::StreamReader* zReader )
  184. {
  185. zReader->lese( (char*)blockIds, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof( unsigned short ) );
  186. for( int x = 0; x < CHUNK_SIZE; x++ )
  187. {
  188. for( int y = 0; y < CHUNK_SIZE; y++ )
  189. {
  190. for( int z = 0; z < WORLD_HEIGHT; z++ )
  191. {
  192. unsigned short blockType;
  193. zReader->lese( (char*)&blockType, 2 );
  194. Block* block = STATIC_REGISTRY( BlockType ).zElement( blockType )->loadBlock( Framework::Vec3<int>( x + location.x - CHUNK_SIZE / 2, y + location.y - CHUNK_SIZE / 2, z ), zReader );
  195. if( block )
  196. putBlockAt( { x, y, z }, block );
  197. else
  198. {
  199. if( STATIC_REGISTRY( BlockType ).zElement( blockIds[ (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z ] )->needsInstance() )
  200. putBlockAt( { x, y, z }, STATIC_REGISTRY( BlockType ).zElement( blockIds[ (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z ] )->createBlock( { x + location.x - CHUNK_SIZE / 2, y + location.y - CHUNK_SIZE / 2, z } ) );
  201. else
  202. putBlockTypeAt( { x, y, z }, blockIds[ (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z ] );
  203. }
  204. }
  205. }
  206. }
  207. }
  208. int Chunk::getDimensionId() const
  209. {
  210. return dimensionId;
  211. }
  212. Framework::Punkt Chunk::getCenter() const
  213. {
  214. return location;
  215. }
  216. Framework::Vec3<int> Chunk::getMin() const
  217. {
  218. return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
  219. }
  220. Framework::Vec3<int> Chunk::getMax() const
  221. {
  222. return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
  223. }