Chunk.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. #include <InMemoryBuffer.h>
  2. #include "Chunk.h"
  3. #include "Constants.h"
  4. #include "Game.h"
  5. #include "NoBlock.h"
  6. Chunk::Chunk(Framework::Punkt location, int dimensionId)
  7. : ReferenceCounter(),
  8. dimensionId(dimensionId),
  9. location(location),
  10. added(0)
  11. {
  12. blocks = new Block * [CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  13. blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  14. lightData = new unsigned char[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6];
  15. memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
  16. memset(blockIds, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
  17. memset(lightData, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
  18. zNeighbours[0] = 0;
  19. zNeighbours[1] = 0;
  20. zNeighbours[2] = 0;
  21. zNeighbours[3] = 0;
  22. }
  23. Chunk::Chunk(Framework::Punkt location, int dimensionId, Framework::StreamReader* zReader)
  24. : Chunk(location, dimensionId)
  25. {
  26. load(zReader);
  27. }
  28. Chunk::~Chunk()
  29. {
  30. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  31. {
  32. if (blocks[i])
  33. blocks[i]->release();
  34. }
  35. delete[] blocks;
  36. delete[] blockIds;
  37. delete[] lightData;
  38. }
  39. void Chunk::addLightSource(int index)
  40. {
  41. for (int i : lightSources)
  42. {
  43. if (i == index)
  44. return;
  45. }
  46. lightSources.add(index);
  47. }
  48. void Chunk::removeLightSource(int index)
  49. {
  50. for (auto i = lightSources.begin(); i; i++)
  51. {
  52. if (i.val() == index)
  53. {
  54. i.remove();
  55. return;
  56. }
  57. }
  58. }
  59. void Chunk::sendLightToClient(Entity* zPlayer)
  60. {
  61. for (int z = 0; z < WORLD_HEIGHT; z++)
  62. {
  63. for (int x = 0; x < CHUNK_SIZE; x++)
  64. {
  65. for (int y = 0; y < CHUNK_SIZE; y++)
  66. {
  67. bool needSend = 0;
  68. for (int i = 0; i < 6; i++)
  69. {
  70. Vec3<int> pos = Vec3<int>(x, y, z) + getDirection(getDirectionFromIndex(i));
  71. if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
  72. {
  73. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0 && pos.y < CHUNK_SIZE)
  74. {
  75. int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
  76. int type = blockIds[bi];
  77. needSend |= type != NoBlockBlockType::ID && type != AirBlockBlockType::ID;
  78. if (needSend)
  79. break;
  80. }
  81. else
  82. {
  83. needSend = 1; // TODO: check if the block is visible
  84. }
  85. }
  86. }
  87. if (needSend)
  88. {
  89. NetworkMessage msg;
  90. msg.addressChunck(this);
  91. char message[11];
  92. message[0] = 1;
  93. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  94. *(int*)(message + 1) = index;
  95. memcpy(message + 5, lightData + index * 6, 6);
  96. msg.setMessage(message, 11, 0);
  97. Game::INSTANCE->sendMessage(&msg, zPlayer);
  98. }
  99. }
  100. }
  101. }
  102. }
  103. Framework::Either<Block*, int> Chunk::zBlockNeighbor(Framework::Vec3<int> location)
  104. {
  105. if (location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0 && location.y < CHUNK_SIZE && location.z >= 0 && location.z < WORLD_HEIGHT)
  106. {
  107. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  108. if (blocks[index])
  109. return blocks[index];
  110. else
  111. return (int)blockIds[index];
  112. }
  113. if (added && location.z >= 0 && location.z < WORLD_HEIGHT)
  114. return Game::INSTANCE->zBlockAt({ location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId);
  115. return 0;
  116. }
  117. void Chunk::notifyObservers(NetworkMessage& msg)
  118. {
  119. Array<int> remove;
  120. int index = 0;
  121. for (int id : observers)
  122. {
  123. Entity* zE = Game::INSTANCE->zEntity(id);
  124. if (!zE)
  125. remove.add(index, 0);
  126. else
  127. Game::INSTANCE->sendMessage(&msg, zE);
  128. index++;
  129. }
  130. for (int i : remove)
  131. observers.remove(i);
  132. }
  133. void Chunk::addObserver(Entity* zEntity)
  134. {
  135. for (int id : observers)
  136. {
  137. if (id == zEntity->getId())
  138. return;
  139. }
  140. observers.add(zEntity->getId());
  141. InMemoryBuffer buffer;
  142. buffer.schreibe("\4", 1);
  143. buffer.schreibe((char*)&location.x, 4);
  144. buffer.schreibe((char*)&location.y, 4);
  145. sendToClient(&buffer);
  146. NetworkMessage msg;
  147. msg.addressDimension();
  148. char* message = new char[buffer.getSize()];
  149. buffer.lese(message, (int)buffer.getSize());
  150. msg.setMessage(message, (int)buffer.getSize(), 1);
  151. msg.setUseBackground();
  152. Game::INSTANCE->sendMessage(&msg, zEntity);
  153. sendLightToClient(zEntity);
  154. }
  155. void Chunk::removeObserver(Entity* zEntity)
  156. {
  157. int index = 0;
  158. for (int id : observers)
  159. {
  160. if (id == zEntity->getId())
  161. {
  162. observers.remove(index);
  163. return;
  164. }
  165. index++;
  166. }
  167. }
  168. void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource)
  169. {
  170. // TODO: answer api messages
  171. char type;
  172. zRequest->lese(&type, 1);
  173. switch (type)
  174. {
  175. case 0:
  176. // register observer
  177. addObserver(zSource);
  178. break;
  179. case 1:
  180. // unsubscribe
  181. removeObserver(zSource);
  182. break;
  183. }
  184. }
  185. void Chunk::initializeLightning()
  186. {
  187. unsigned char dayLight[6] = { 255, 255, 255, 0, 0, 0 };
  188. unsigned char noLight[6] = { 0, 0, 0, 0, 0, 0 };
  189. while (true)
  190. {
  191. bool changes = false;
  192. for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
  193. {
  194. for (int x = 0; x < CHUNK_SIZE; x++)
  195. {
  196. for (int y = 0; y < CHUNK_SIZE; y++)
  197. {
  198. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  199. unsigned char* light = getLightData(Vec3<int>(x, y, z));
  200. unsigned char newLight[6] = { 0, 0, 0, 0, 0, 0 };
  201. for (int i = 0; i < 6; i++)
  202. {
  203. unsigned char* neighborLeight;
  204. Vec3<int> neighborPos = Vec3<int>(x, y, z) + getDirection(getDirectionFromIndex(i));
  205. if (neighborPos.z < 0 || neighborPos.x < 0 || neighborPos.y < 0 || neighborPos.x >= CHUNK_SIZE || neighborPos.y >= CHUNK_SIZE)
  206. {
  207. neighborLeight = noLight;
  208. }
  209. else if (neighborPos.z >= WORLD_HEIGHT)
  210. {
  211. neighborLeight = dayLight;
  212. }
  213. else
  214. {
  215. neighborLeight = getLightData(Vec3<int>(x, y, neighborPos.z));
  216. }
  217. for (int j = 0; j < 3; j++)
  218. newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : neighborLeight[j] - 16);
  219. for (int j = 3; j < 6; j++)
  220. newLight[j] = (unsigned char)MAX(newLight[j], neighborLeight[j] - 16);
  221. }
  222. const Block* current = blocks[index] ? blocks[index] : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->zDefault();
  223. // add own light emission
  224. for (int j = 3; j < 6; j++)
  225. newLight[j] = (unsigned char)MAX(newLight[j], current->getLightEmisionColor()[j - 3]);
  226. current->filterPassingLight(newLight);
  227. current->filterPassingLight(newLight + 3);
  228. for (int i = 0; i < 6; i++)
  229. {
  230. if (newLight[i] != light[i])
  231. {
  232. changes = 1;
  233. memcpy(light, newLight, 6);
  234. }
  235. }
  236. }
  237. }
  238. }
  239. if (!changes)
  240. break;
  241. }
  242. }
  243. Framework::Either<Block*, int> Chunk::zBlockAt(Framework::Vec3<int> location) const
  244. {
  245. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  246. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  247. if (blocks[index])
  248. return blocks[index];
  249. else
  250. return (int)blockIds[index];
  251. }
  252. const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
  253. {
  254. auto b = zBlockAt(location);
  255. if (b.isA())
  256. return b;
  257. if (b.getB())
  258. return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->zDefault();
  259. return 0;
  260. }
  261. void Chunk::instantiateBlock(Framework::Vec3<int> location)
  262. {
  263. auto b = zBlockAt(location);
  264. if (b.isA())
  265. return;
  266. if (!b.getB())
  267. generateBlock(location);
  268. b = zBlockAt(location);
  269. if (b.isB())
  270. 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));
  271. }
  272. void Chunk::generateBlock(Framework::Vec3<int> location)
  273. {
  274. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  275. if (blockIds[index])
  276. return;
  277. 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);
  278. if (generated.isA())
  279. putBlockAt(location, generated);
  280. else
  281. putBlockTypeAt(location, generated);
  282. }
  283. void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
  284. {
  285. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  286. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT&& index >= 0);
  287. Block* old = blocks[index];
  288. bool change = 0;
  289. bool wasLightSource = old ? old->zBlockType()->isLightSource() : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->isLightSource();
  290. bool isLightSource = 0;
  291. if (block)
  292. {
  293. change = blockIds[index] != (unsigned short)block->zBlockType()->getId();
  294. blockIds[index] = (unsigned short)block->zBlockType()->getId();
  295. isLightSource = block->zBlockType()->isLightSource();
  296. }
  297. else
  298. {
  299. change = old != 0;
  300. }
  301. blocks[index] = block;
  302. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  303. if (neighbor.isA())
  304. ((Block*)neighbor)->setNeighbour(SOUTH, block);
  305. if (block)
  306. block->setNeighbour(NORTH, neighbor);
  307. neighbor = zBlockNeighbor(location + getDirection(EAST));
  308. if (neighbor.isA())
  309. ((Block*)neighbor)->setNeighbour(WEST, block);
  310. if (block)
  311. block->setNeighbour(EAST, neighbor);
  312. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  313. if (neighbor.isA())
  314. ((Block*)neighbor)->setNeighbour(NORTH, block);
  315. if (block)
  316. block->setNeighbour(SOUTH, neighbor);
  317. neighbor = zBlockNeighbor(location + getDirection(WEST));
  318. if (neighbor.isA())
  319. ((Block*)neighbor)->setNeighbour(EAST, block);
  320. if (block)
  321. block->setNeighbour(WEST, neighbor);
  322. neighbor = zBlockNeighbor(location + getDirection(TOP));
  323. if (neighbor.isA())
  324. ((Block*)neighbor)->setNeighbour(BOTTOM, block);
  325. if (block)
  326. block->setNeighbour(TOP, neighbor);
  327. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  328. if (neighbor.isA())
  329. ((Block*)neighbor)->setNeighbour(TOP, block);
  330. if (block)
  331. block->setNeighbour(BOTTOM, neighbor);
  332. if (old)
  333. old->release();
  334. if (change)
  335. {
  336. if (isLightSource != wasLightSource)
  337. {
  338. if (isLightSource)
  339. addLightSource(index);
  340. else
  341. removeLightSource(index);
  342. }
  343. if (added)
  344. {
  345. char msg[9];
  346. msg[0] = 0; // set block
  347. *(int*)(msg + 1) = index;
  348. *(int*)(msg + 5) = block ? block->zBlockType()->getId() : NoBlockBlockType::ID;
  349. NetworkMessage message;
  350. message.addressChunck(this);
  351. message.setMessage(msg, 9, 0);
  352. notifyObservers(message);
  353. Game::INSTANCE->updateLightning(getDimensionId(), Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z));
  354. }
  355. }
  356. }
  357. void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
  358. {
  359. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  360. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  361. bool wasLightSource = StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->isLightSource();
  362. bool isLightSource = StaticRegistry<BlockType>::INSTANCE.zElement(type)->isLightSource();
  363. if (blockIds[index] != (unsigned short)type)
  364. {
  365. blockIds[index] = (unsigned short)type;
  366. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  367. if (neighbor.isA())
  368. ((Block*)neighbor)->setNeighbourType(SOUTH, type);
  369. neighbor = zBlockNeighbor(location + getDirection(EAST));
  370. if (neighbor.isA())
  371. ((Block*)neighbor)->setNeighbourType(WEST, type);
  372. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  373. if (neighbor.isA())
  374. ((Block*)neighbor)->setNeighbourType(NORTH, type);
  375. neighbor = zBlockNeighbor(location + getDirection(WEST));
  376. if (neighbor.isA())
  377. ((Block*)neighbor)->setNeighbourType(EAST, type);
  378. neighbor = zBlockNeighbor(location + getDirection(TOP));
  379. if (neighbor.isA())
  380. ((Block*)neighbor)->setNeighbourType(BOTTOM, type);
  381. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  382. if (neighbor.isA())
  383. ((Block*)neighbor)->setNeighbourType(TOP, type);
  384. if (isLightSource != wasLightSource)
  385. {
  386. if (isLightSource)
  387. addLightSource(index);
  388. else
  389. removeLightSource(index);
  390. }
  391. if (added)
  392. {
  393. char msg[9];
  394. msg[0] = 0; // set block
  395. *(int*)(msg + 1) = index;
  396. *(int*)(msg + 5) = type;
  397. NetworkMessage message;
  398. message.addressChunck(this);
  399. message.setMessage(msg, 9, 0);
  400. notifyObservers(message);
  401. Game::INSTANCE->updateLightning(getDimensionId(), Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z));
  402. }
  403. }
  404. }
  405. void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
  406. {
  407. zNeighbours[getDirectionIndex(dir)] = zChunk;
  408. for (int i = 0; i < CHUNK_SIZE; i++)
  409. {
  410. for (int z = 0; z < WORLD_HEIGHT; z++)
  411. {
  412. if (dir == NORTH)
  413. {
  414. int index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  415. if (blocks[index])
  416. {
  417. int j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  418. if (zChunk && zChunk->blocks[j])
  419. blocks[index]->setNeighbour(NORTH, zChunk->blocks[j]);
  420. else
  421. {
  422. blocks[index]->setNeighbour(NORTH, 0);
  423. blocks[index]->setNeighbourType(NORTH, zChunk ? zChunk->blockIds[j] : 0);
  424. }
  425. }
  426. }
  427. else if (dir == EAST)
  428. {
  429. int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  430. if (blocks[index])
  431. {
  432. int j = i * WORLD_HEIGHT + z;
  433. if (zChunk && zChunk->blocks[j])
  434. blocks[index]->setNeighbour(EAST, zChunk->blocks[j]);
  435. else
  436. {
  437. blocks[index]->setNeighbour(EAST, 0);
  438. blocks[index]->setNeighbourType(EAST, zChunk ? zChunk->blockIds[j] : 0);
  439. }
  440. }
  441. }
  442. else if (dir == SOUTH)
  443. {
  444. int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  445. if (blocks[index])
  446. {
  447. int j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  448. if (zChunk && zChunk->blocks[j])
  449. blocks[index]->setNeighbour(SOUTH, zChunk->blocks[j]);
  450. else
  451. {
  452. blocks[index]->setNeighbour(SOUTH, 0);
  453. blocks[index]->setNeighbourType(SOUTH, zChunk ? zChunk->blockIds[j] : 0);
  454. }
  455. }
  456. }
  457. else if (dir == WEST)
  458. {
  459. int index = i * WORLD_HEIGHT + z;
  460. if (blocks[index])
  461. {
  462. int j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  463. if (zChunk && zChunk->blocks[j])
  464. blocks[index]->setNeighbour(WEST, zChunk->blocks[j]);
  465. else
  466. {
  467. blocks[index]->setNeighbour(WEST, 0);
  468. blocks[index]->setNeighbourType(WEST, zChunk ? zChunk->blockIds[j] : 0);
  469. }
  470. }
  471. }
  472. }
  473. }
  474. }
  475. void Chunk::load(Framework::StreamReader* zReader)
  476. {
  477. unsigned short id = 0;
  478. zReader->lese((char*)&id, 2);
  479. Framework::Vec3<int> pos;
  480. bool d = 0;
  481. while (id)
  482. {
  483. zReader->lese((char*)&pos.x, 4);
  484. zReader->lese((char*)&pos.y, 4);
  485. zReader->lese((char*)&pos.z, 4);
  486. zReader->lese((char*)&d, 1);
  487. if (d)
  488. 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));
  489. else
  490. putBlockTypeAt(pos, id);
  491. zReader->lese((char*)&id, 2);
  492. }
  493. initializeLightning();
  494. }
  495. void Chunk::save(Framework::StreamWriter* zWriter)
  496. {
  497. for (int x = 0; x < CHUNK_SIZE; x++)
  498. {
  499. for (int y = 0; y < CHUNK_SIZE; y++)
  500. {
  501. for (int z = 0; z < WORLD_HEIGHT; z++)
  502. {
  503. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  504. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  505. if (blockType)
  506. {
  507. zWriter->schreibe((char*)&blockType, 2);
  508. zWriter->schreibe((char*)&x, 4);
  509. zWriter->schreibe((char*)&y, 4);
  510. zWriter->schreibe((char*)&z, 4);
  511. if (blocks[index])
  512. {
  513. bool d = 1;
  514. zWriter->schreibe((char*)&d, 1);
  515. StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->saveBlock(blocks[index], zWriter);
  516. }
  517. else
  518. {
  519. bool d = 0;
  520. zWriter->schreibe((char*)&d, 1);
  521. }
  522. }
  523. }
  524. }
  525. }
  526. unsigned short end = 0;
  527. zWriter->schreibe((char*)&end, 2);
  528. }
  529. void Chunk::sendToClient(Framework::StreamWriter* zWriter)
  530. {
  531. for (int x = 0; x < CHUNK_SIZE; x++)
  532. {
  533. for (int y = 0; y < CHUNK_SIZE; y++)
  534. {
  535. for (int z = 0; z < WORLD_HEIGHT; z++)
  536. {
  537. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  538. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  539. if (blockType)
  540. {
  541. bool visible = 0;
  542. if (!visible)
  543. {
  544. if (!blocks[index])
  545. {
  546. if (CONST_BLOCK(0, blockIds[index])->isTransparent() || CONST_BLOCK(0, blockIds[index])->isPassable())
  547. visible = 1;
  548. else
  549. {
  550. for (int d = 0; d < 6 && !visible; d++)
  551. {
  552. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  553. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  554. visible = 1;
  555. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  556. visible = 1;
  557. }
  558. }
  559. }
  560. else
  561. visible = blocks[index]->isVisible();
  562. }
  563. if (visible && (blocks[index] || blockType != AirBlockBlockType::ID))
  564. {
  565. zWriter->schreibe((char*)&blockType, 2);
  566. zWriter->schreibe((char*)&index, 4);
  567. }
  568. }
  569. }
  570. }
  571. }
  572. unsigned short end = 0;
  573. zWriter->schreibe((char*)&end, 2);
  574. }
  575. void Chunk::removeUnusedBlocks()
  576. {
  577. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  578. {
  579. if (blocks[i])
  580. {
  581. if (!blocks[i]->isVisible())
  582. {
  583. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  584. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  585. int z = i % WORLD_HEIGHT;
  586. putBlockAt({ x,y,z }, 0);
  587. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  588. }
  589. }
  590. else if (blockIds[i])
  591. {
  592. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  593. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  594. int z = i % WORLD_HEIGHT;
  595. bool visible = 0;
  596. if (CONST_BLOCK(0, blockIds[i])->isTransparent() || CONST_BLOCK(0, blockIds[i])->isPassable())
  597. visible = 1;
  598. else
  599. {
  600. for (int d = 0; d < 6 && !visible; d++)
  601. {
  602. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  603. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  604. visible = 1;
  605. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  606. visible = 1;
  607. }
  608. }
  609. if (!visible)
  610. {
  611. putBlockAt({ x,y,z }, 0);
  612. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  613. }
  614. }
  615. }
  616. int count = 0;
  617. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  618. {
  619. if (blockIds[i] && blockIds[i] != AirBlockBlockType::ID)
  620. count++;
  621. }
  622. std::cout << "chunk " << location.x << ", " << location.y << " was generated with " << count << " blocks.\n";
  623. }
  624. int Chunk::getDimensionId() const
  625. {
  626. return dimensionId;
  627. }
  628. Framework::Punkt Chunk::getCenter() const
  629. {
  630. return location;
  631. }
  632. Framework::Vec3<int> Chunk::getMin() const
  633. {
  634. return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
  635. }
  636. Framework::Vec3<int> Chunk::getMax() const
  637. {
  638. return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
  639. }
  640. void Chunk::prepareRemove()
  641. {
  642. added = 0;
  643. for (int i = 0; i < 4; i++)
  644. {
  645. if (zNeighbours[i])
  646. {
  647. zNeighbours[i]->setNeighbor(getOppositeDirection(getDirectionFromIndex(i)), 0);
  648. zNeighbours[i] = 0;
  649. }
  650. }
  651. }
  652. void Chunk::setAdded()
  653. {
  654. added = 1;
  655. }
  656. bool Chunk::hasObservers() const
  657. {
  658. return observers.getEintragAnzahl() > 0;
  659. }
  660. unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
  661. {
  662. int index = ((location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z) * 6;
  663. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  664. return lightData + index;
  665. }
  666. void Chunk::setLightData(Framework::Vec3<int> location, unsigned char* data)
  667. {
  668. int index = ((location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z) * 6;
  669. memcpy(lightData + index, data, 6);
  670. // check if neighbor is a visible block and send update to clients
  671. bool needSend = 0;
  672. for (int i = 0; i < 6; i++)
  673. {
  674. Vec3<int> pos = location + getDirection(getDirectionFromIndex(i));
  675. if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
  676. {
  677. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0 && pos.y < CHUNK_SIZE)
  678. {
  679. int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
  680. int type = blockIds[bi];
  681. needSend |= type != NoBlockBlockType::ID && type != AirBlockBlockType::ID;
  682. if (needSend)
  683. break;
  684. }
  685. else
  686. {
  687. needSend = 1; // TODO: check if the block is visible
  688. }
  689. }
  690. }
  691. if (needSend)
  692. {
  693. NetworkMessage msg;
  694. msg.addressChunck(this);
  695. char message[11];
  696. message[0] = 1;
  697. *(int*)(message + 1) = index / 6;
  698. memcpy(message + 5, data, 6);
  699. msg.setMessage(message, 11, 0);
  700. notifyObservers(msg);
  701. }
  702. }