Chunk.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #include "Chunk.h"
  2. #include "Constants.h"
  3. #include "Game.h"
  4. #include "NoBlock.h"
  5. Chunk::Chunk(Framework::Punkt location, int dimensionId)
  6. : ReferenceCounter(),
  7. dimensionId(dimensionId),
  8. location(location),
  9. added(0)
  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 (added && location.z >= 0 && location.z < WORLD_HEIGHT)
  46. return Game::INSTANCE->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. void Chunk::api(Framework::StreamReader* zRequest, NetworkResponse* zResponse)
  50. {
  51. // TODO: answer api messages
  52. }
  53. Framework::Either<Block*, int> Chunk::zBlockAt(Framework::Vec3<int> location) const
  54. {
  55. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  56. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  57. if (blocks[index])
  58. return blocks[index];
  59. else
  60. return (int)blockIds[index];
  61. }
  62. const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
  63. {
  64. auto b = zBlockAt(location);
  65. if (b.isA())
  66. return b;
  67. if (b.getB())
  68. return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->zDefault();
  69. return 0;
  70. }
  71. void Chunk::instantiateBlock(Framework::Vec3<int> location)
  72. {
  73. auto b = zBlockAt(location);
  74. if (b.isA())
  75. return;
  76. if (!b.getB())
  77. generateBlock(location);
  78. b = zBlockAt(location);
  79. if (b.isB())
  80. putBlockAt(location, StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->createBlockAt({ location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, 0));
  81. }
  82. void Chunk::generateBlock(Framework::Vec3<int> location)
  83. {
  84. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  85. if (blockIds[index])
  86. return;
  87. auto generated = Game::INSTANCE->zGenerator()->generateSingleBlock({ location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId);
  88. if (generated.isA())
  89. putBlockAt(location, generated);
  90. else
  91. putBlockTypeAt(location, generated);
  92. }
  93. void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
  94. {
  95. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  96. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT&& index >= 0);
  97. Block* old = blocks[index];
  98. if (block)
  99. blockIds[index] = (unsigned short)block->zBlockType()->getId();
  100. blocks[index] = block;
  101. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  102. if (neighbor.isA())
  103. ((Block*)neighbor)->setNeighbour(SOUTH, block);
  104. if (block)
  105. block->setNeighbour(NORTH, neighbor);
  106. neighbor = zBlockNeighbor(location + getDirection(EAST));
  107. if (neighbor.isA())
  108. ((Block*)neighbor)->setNeighbour(WEST, block);
  109. if (block)
  110. block->setNeighbour(EAST, neighbor);
  111. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  112. if (neighbor.isA())
  113. ((Block*)neighbor)->setNeighbour(NORTH, block);
  114. if (block)
  115. block->setNeighbour(SOUTH, neighbor);
  116. neighbor = zBlockNeighbor(location + getDirection(WEST));
  117. if (neighbor.isA())
  118. ((Block*)neighbor)->setNeighbour(EAST, block);
  119. if (block)
  120. block->setNeighbour(WEST, neighbor);
  121. neighbor = zBlockNeighbor(location + getDirection(TOP));
  122. if (neighbor.isA())
  123. ((Block*)neighbor)->setNeighbour(BOTTOM, block);
  124. if (block)
  125. block->setNeighbour(TOP, neighbor);
  126. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  127. if (neighbor.isA())
  128. ((Block*)neighbor)->setNeighbour(TOP, block);
  129. if (block)
  130. block->setNeighbour(BOTTOM, neighbor);
  131. if (old)
  132. old->release();
  133. }
  134. void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
  135. {
  136. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  137. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  138. blockIds[index] = (unsigned short)type;
  139. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  140. if (neighbor.isA())
  141. ((Block*)neighbor)->setNeighbourType(SOUTH, type);
  142. neighbor = zBlockNeighbor(location + getDirection(EAST));
  143. if (neighbor.isA())
  144. ((Block*)neighbor)->setNeighbourType(WEST, type);
  145. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  146. if (neighbor.isA())
  147. ((Block*)neighbor)->setNeighbourType(NORTH, type);
  148. neighbor = zBlockNeighbor(location + getDirection(WEST));
  149. if (neighbor.isA())
  150. ((Block*)neighbor)->setNeighbourType(EAST, type);
  151. neighbor = zBlockNeighbor(location + getDirection(TOP));
  152. if (neighbor.isA())
  153. ((Block*)neighbor)->setNeighbourType(BOTTOM, type);
  154. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  155. if (neighbor.isA())
  156. ((Block*)neighbor)->setNeighbourType(TOP, type);
  157. }
  158. void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
  159. {
  160. zNeighbours[getDirectionIndex(dir)] = zChunk;
  161. for (int i = 0; i < CHUNK_SIZE; i++)
  162. {
  163. for (int z = 0; z < WORLD_HEIGHT; z++)
  164. {
  165. if (dir == NORTH)
  166. {
  167. int index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  168. if (blocks[index])
  169. {
  170. int j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  171. if (zChunk && zChunk->blocks[j])
  172. blocks[index]->setNeighbour(NORTH, zChunk->blocks[j]);
  173. else
  174. {
  175. blocks[index]->setNeighbour(NORTH, 0);
  176. blocks[index]->setNeighbourType(NORTH, zChunk ? zChunk->blockIds[j] : 0);
  177. }
  178. }
  179. }
  180. else if (dir == EAST)
  181. {
  182. int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  183. if (blocks[index])
  184. {
  185. int j = i * WORLD_HEIGHT + z;
  186. if (zChunk && zChunk->blocks[j])
  187. blocks[index]->setNeighbour(EAST, zChunk->blocks[j]);
  188. else
  189. {
  190. blocks[index]->setNeighbour(EAST, 0);
  191. blocks[index]->setNeighbourType(EAST, zChunk ? zChunk->blockIds[j] : 0);
  192. }
  193. }
  194. }
  195. else if (dir == SOUTH)
  196. {
  197. int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  198. if (blocks[index])
  199. {
  200. int j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  201. if (zChunk && zChunk->blocks[j])
  202. blocks[index]->setNeighbour(SOUTH, zChunk->blocks[j]);
  203. else
  204. {
  205. blocks[index]->setNeighbour(SOUTH, 0);
  206. blocks[index]->setNeighbourType(SOUTH, zChunk ? zChunk->blockIds[j] : 0);
  207. }
  208. }
  209. }
  210. else if (dir == WEST)
  211. {
  212. int index = i * WORLD_HEIGHT + z;
  213. if (blocks[index])
  214. {
  215. int j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  216. if (zChunk && zChunk->blocks[j])
  217. blocks[index]->setNeighbour(WEST, zChunk->blocks[j]);
  218. else
  219. {
  220. blocks[index]->setNeighbour(WEST, 0);
  221. blocks[index]->setNeighbourType(WEST, zChunk ? zChunk->blockIds[j] : 0);
  222. }
  223. }
  224. }
  225. }
  226. }
  227. }
  228. void Chunk::load(Framework::StreamReader* zReader)
  229. {
  230. unsigned short id = 0;
  231. zReader->lese((char*)&id, 2);
  232. Framework::Vec3<int> pos;
  233. bool d = 0;
  234. while (id)
  235. {
  236. zReader->lese((char*)&pos.x, 4);
  237. zReader->lese((char*)&pos.y, 4);
  238. zReader->lese((char*)&pos.z, 4);
  239. zReader->lese((char*)&d, 1);
  240. if (d)
  241. putBlockAt(pos, StaticRegistry<BlockType>::INSTANCE.zElement(id)->loadBlock(Framework::Vec3<int>(pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z), zReader));
  242. else
  243. putBlockTypeAt(pos, id);
  244. zReader->lese((char*)&id, 2);
  245. }
  246. }
  247. void Chunk::save(Framework::StreamWriter* zWriter)
  248. {
  249. for (int x = 0; x < CHUNK_SIZE; x++)
  250. {
  251. for (int y = 0; y < CHUNK_SIZE; y++)
  252. {
  253. for (int z = 0; z < WORLD_HEIGHT; z++)
  254. {
  255. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  256. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  257. if (blockType)
  258. {
  259. zWriter->schreibe((char*)&blockType, 2);
  260. zWriter->schreibe((char*)&x, 4);
  261. zWriter->schreibe((char*)&y, 4);
  262. zWriter->schreibe((char*)&z, 4);
  263. if (blocks[index])
  264. {
  265. bool d = 1;
  266. zWriter->schreibe((char*)&d, 1);
  267. StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->saveBlock(blocks[index], zWriter);
  268. }
  269. else
  270. {
  271. bool d = 0;
  272. zWriter->schreibe((char*)&d, 1);
  273. }
  274. }
  275. }
  276. }
  277. }
  278. unsigned short end = 0;
  279. zWriter->schreibe((char*)&end, 2);
  280. }
  281. void Chunk::sendToClient(Framework::StreamWriter* zWriter)
  282. {
  283. for (int x = 0; x < CHUNK_SIZE; x++)
  284. {
  285. for (int y = 0; y < CHUNK_SIZE; y++)
  286. {
  287. for (int z = 0; z < WORLD_HEIGHT; z++)
  288. {
  289. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  290. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  291. if (blockType)
  292. {
  293. bool visible = 0;
  294. if (!visible)
  295. {
  296. if (!blocks[index])
  297. {
  298. if (CONST_BLOCK(0, blockIds[index])->isTransparent() || CONST_BLOCK(0, blockIds[index])->isPassable())
  299. visible = 1;
  300. else
  301. {
  302. for (int d = 0; d < 6 && !visible; d++)
  303. {
  304. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  305. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  306. visible = 1;
  307. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  308. visible = 1;
  309. }
  310. }
  311. }
  312. else
  313. visible = blocks[index]->isVisible();
  314. }
  315. if (visible && (blocks[index] || blockType != AirBlockBlockType::ID))
  316. {
  317. zWriter->schreibe((char*)&blockType, 2);
  318. zWriter->schreibe((char*)&x, 4);
  319. zWriter->schreibe((char*)&y, 4);
  320. zWriter->schreibe((char*)&z, 4);
  321. }
  322. }
  323. }
  324. }
  325. }
  326. unsigned short end = 0;
  327. zWriter->schreibe((char*)&end, 2);
  328. }
  329. void Chunk::removeUnusedBlocks()
  330. {
  331. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  332. {
  333. if (blocks[i])
  334. {
  335. if (!blocks[i]->isVisible())
  336. {
  337. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  338. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  339. int z = i % WORLD_HEIGHT;
  340. putBlockAt({ x,y,z }, 0);
  341. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  342. }
  343. }
  344. else if (blockIds[i])
  345. {
  346. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  347. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  348. int z = i % WORLD_HEIGHT;
  349. bool visible = 0;
  350. if (CONST_BLOCK(0, blockIds[i])->isTransparent() || CONST_BLOCK(0, blockIds[i])->isPassable())
  351. visible = 1;
  352. else
  353. {
  354. for (int d = 0; d < 6 && !visible; d++)
  355. {
  356. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  357. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  358. visible = 1;
  359. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  360. visible = 1;
  361. }
  362. }
  363. if (!visible)
  364. {
  365. putBlockAt({ x,y,z }, 0);
  366. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  367. }
  368. }
  369. }
  370. int count = 0;
  371. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  372. {
  373. if (blockIds[i] && blockIds[i] != AirBlockBlockType::ID)
  374. count++;
  375. }
  376. std::cout << "chunk " << location.x << ", " << location.y << " was generated with " << count << " blocks.\n";
  377. }
  378. int Chunk::getDimensionId() const
  379. {
  380. return dimensionId;
  381. }
  382. Framework::Punkt Chunk::getCenter() const
  383. {
  384. return location;
  385. }
  386. Framework::Vec3<int> Chunk::getMin() const
  387. {
  388. return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
  389. }
  390. Framework::Vec3<int> Chunk::getMax() const
  391. {
  392. return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
  393. }
  394. void Chunk::prepareRemove()
  395. {
  396. added = 0;
  397. for (int i = 0; i < 4; i++)
  398. {
  399. if (zNeighbours[i])
  400. {
  401. zNeighbours[i]->setNeighbor(getOppositeDirection(getDirectionFromIndex(i)), 0);
  402. zNeighbours[i] = 0;
  403. }
  404. }
  405. }
  406. void Chunk::setAdded()
  407. {
  408. added = 1;
  409. }
  410. void Chunk::addView(Entity* zEntity)
  411. {
  412. cs.lock();
  413. bool found = 0;
  414. for (Entity* e : views)
  415. {
  416. if (e == zEntity)
  417. {
  418. found = 1;
  419. break;
  420. }
  421. }
  422. if (!found)
  423. views.add(zEntity);
  424. cs.unlock();
  425. }
  426. void Chunk::removeView(Entity* zEntity)
  427. {
  428. cs.lock();
  429. int i = 0;
  430. for (Entity* e : views)
  431. {
  432. if (e == zEntity)
  433. {
  434. views.remove(i);
  435. break;
  436. }
  437. i++;
  438. }
  439. cs.unlock();
  440. }
  441. bool Chunk::hasView(Entity* zEntity)
  442. {
  443. cs.lock();
  444. for (Entity* e : views)
  445. {
  446. if (e == zEntity)
  447. {
  448. cs.unlock();
  449. return 1;
  450. }
  451. }
  452. cs.unlock();
  453. return 0;
  454. }
  455. bool Chunk::hasViews() const
  456. {
  457. return views.getEintragAnzahl() > 0;
  458. }