Chunk.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. #include "Chunk.h"
  2. #include <AsynchronCall.h>
  3. #include <InMemoryBuffer.h>
  4. #include "Constants.h"
  5. #include "Game.h"
  6. #include "NoBlock.h"
  7. Chunk::Chunk(Framework::Punkt location, int dimensionId)
  8. : ReferenceCounter(),
  9. dimensionId(dimensionId),
  10. location(location),
  11. added(0),
  12. currentlyLoading(1)
  13. {
  14. blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  15. blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  16. lightData = new unsigned char[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6];
  17. memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
  18. memset(blockIds,
  19. 0,
  20. CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
  21. memset(lightData, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
  22. zNeighbours[0] = 0;
  23. zNeighbours[1] = 0;
  24. zNeighbours[2] = 0;
  25. zNeighbours[3] = 0;
  26. }
  27. Chunk::Chunk(Framework::Punkt location,
  28. int dimensionId,
  29. Framework::StreamReader* zReader)
  30. : Chunk(location, dimensionId)
  31. {
  32. load(zReader);
  33. }
  34. Chunk::~Chunk()
  35. {
  36. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  37. {
  38. if (blocks[i]) blocks[i]->release();
  39. }
  40. delete[] blocks;
  41. delete[] blockIds;
  42. delete[] lightData;
  43. }
  44. void Chunk::lock()
  45. {
  46. cs.lock();
  47. }
  48. void Chunk::unlock()
  49. {
  50. cs.unlock();
  51. }
  52. void Chunk::tick(TickQueue* zQueue)
  53. {
  54. for (Block* source : tickSources)
  55. zQueue->addToQueue(source);
  56. }
  57. void Chunk::postTick() {}
  58. void Chunk::addLightSource(int index)
  59. {
  60. for (int i : lightSources)
  61. {
  62. if (i == index) return;
  63. }
  64. lightSources.add(index);
  65. }
  66. void Chunk::removeLightSource(int index)
  67. {
  68. for (auto i = lightSources.begin(); i; i++)
  69. {
  70. if (i.val() == index)
  71. {
  72. i.remove();
  73. return;
  74. }
  75. }
  76. }
  77. void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
  78. {
  79. for (int z = 0; z < WORLD_HEIGHT; z++)
  80. {
  81. for (int x = -1; x <= CHUNK_SIZE; x++)
  82. {
  83. for (int y = -1; y <= CHUNK_SIZE; y++)
  84. {
  85. if ((x < 0 || x == CHUNK_SIZE) && (y < 0 || y > CHUNK_SIZE))
  86. {
  87. continue;
  88. }
  89. bool needSend = 0;
  90. for (int i = 0; i < 6; i++)
  91. {
  92. Vec3<int> pos = Vec3<int>(x, y, z)
  93. + getDirection(getDirectionFromIndex(i));
  94. if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
  95. {
  96. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
  97. && pos.y < CHUNK_SIZE)
  98. {
  99. int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT
  100. + pos.z;
  101. int type = blockIds[bi];
  102. needSend |= type != BlockTypeEnum::NO_BLOCK
  103. && type != BlockTypeEnum::AIR;
  104. }
  105. else
  106. {
  107. if (x >= 0 && x < CHUNK_SIZE && y >= 0
  108. && y < CHUNK_SIZE)
  109. {
  110. if (i < 4 && zNeighbours[i])
  111. {
  112. Vec3<int> offset
  113. = getDirection(getDirectionFromIndex(i))
  114. * 16;
  115. int bi = ((pos.x - offset.x) * CHUNK_SIZE
  116. + (pos.y - offset.y))
  117. * WORLD_HEIGHT
  118. + (pos.z - offset.z);
  119. int type = zNeighbours[i]->blockIds[bi];
  120. needSend |= type != BlockTypeEnum::NO_BLOCK
  121. && type != BlockTypeEnum::AIR;
  122. }
  123. }
  124. }
  125. if (needSend) break;
  126. }
  127. }
  128. if (needSend)
  129. {
  130. if (x >= 0 && x < CHUNK_SIZE && y >= 0 && y < CHUNK_SIZE)
  131. {
  132. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  133. zWriter->schreibe((char*)&index, 4);
  134. zWriter->schreibe((char*)(lightData + index * 6), 6);
  135. }
  136. else
  137. {
  138. int dir;
  139. int index = 0;
  140. if (x == -1)
  141. {
  142. dir = getDirectionIndex(WEST);
  143. index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y)
  144. * WORLD_HEIGHT
  145. + z;
  146. }
  147. else if (y == -1)
  148. {
  149. dir = getDirectionIndex(NORTH);
  150. index = (x * CHUNK_SIZE + CHUNK_SIZE - 1)
  151. * WORLD_HEIGHT
  152. + z;
  153. }
  154. else if (x == CHUNK_SIZE)
  155. {
  156. dir = getDirectionIndex(EAST);
  157. index = y * WORLD_HEIGHT + z;
  158. }
  159. else if (y == CHUNK_SIZE)
  160. {
  161. dir = getDirectionIndex(SOUTH);
  162. index = (x * CHUNK_SIZE) * WORLD_HEIGHT + z;
  163. }
  164. if (zNeighbours[dir])
  165. {
  166. int i = -1;
  167. zWriter->schreibe((char*)&i, 4);
  168. zWriter->schreibe((char*)&x, 4);
  169. zWriter->schreibe((char*)&y, 4);
  170. zWriter->schreibe((char*)&z, 4);
  171. zWriter->schreibe(
  172. (char*)(zNeighbours[dir]->lightData
  173. + index * 6),
  174. 6);
  175. }
  176. }
  177. }
  178. }
  179. }
  180. }
  181. int end = -2;
  182. zWriter->schreibe((char*)&end, 4);
  183. }
  184. void Chunk::broadcastLightData(int index, bool foreground)
  185. {
  186. int x = (index / WORLD_HEIGHT) / CHUNK_SIZE;
  187. int y = (index / WORLD_HEIGHT) % CHUNK_SIZE;
  188. int z = index % WORLD_HEIGHT;
  189. NetworkMessage* msg = new NetworkMessage();
  190. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  191. char* message = new char[19];
  192. message[0] = 5;
  193. *(int*)(message + 1) = x + this->location.x - CHUNK_SIZE / 2;
  194. *(int*)(message + 5) = y + this->location.y - CHUNK_SIZE / 2;
  195. *(int*)(message + 9) = z;
  196. memcpy(message + 13, lightData + index * 6, 6);
  197. msg->setMessage(message, 19);
  198. if (!foreground) msg->setUseBackground();
  199. notifyObservers(msg);
  200. }
  201. Framework::Either<Block*, int> Chunk::zBlockNeighbor(
  202. Framework::Vec3<int> location)
  203. {
  204. if (location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0
  205. && location.y < CHUNK_SIZE && location.z >= 0
  206. && location.z < WORLD_HEIGHT)
  207. {
  208. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT
  209. + location.z;
  210. if (blocks[index])
  211. return blocks[index];
  212. else
  213. return (int)blockIds[index];
  214. }
  215. if (added && location.z >= 0 && location.z < WORLD_HEIGHT)
  216. return Game::INSTANCE->zBlockAt(
  217. {location.x + this->location.x - CHUNK_SIZE / 2,
  218. location.y + this->location.y - CHUNK_SIZE / 2,
  219. location.z},
  220. dimensionId);
  221. return 0;
  222. }
  223. void Chunk::notifyObservers(NetworkMessage* msg)
  224. {
  225. Array<int> remove;
  226. int index = 0;
  227. for (InformationObserver* observer : observers)
  228. {
  229. if (!observer->sendMessage(
  230. dynamic_cast<NetworkMessage*>(msg->getThis())))
  231. {
  232. remove.add(index, 0);
  233. }
  234. index++;
  235. }
  236. for (int i : remove)
  237. observers.remove(i);
  238. msg->release();
  239. }
  240. void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
  241. {
  242. for (InformationObserver* observer : observers)
  243. {
  244. if (observer->getEntityId() == zEntity->getId()) return;
  245. }
  246. int id = zEntity->getId();
  247. InformationObserver* observer = new InformationObserver(id);
  248. observers.add(observer);
  249. laterHandler.addTodo([this, id, observer]() {
  250. InMemoryBuffer buffer;
  251. buffer.schreibe("\4", 1);
  252. buffer.schreibe((char*)&location.x, 4);
  253. buffer.schreibe((char*)&location.y, 4);
  254. sendToClient(&buffer);
  255. sendLightToClient(&buffer);
  256. NetworkMessage* msg = new NetworkMessage();
  257. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  258. std::cout << "chunk size: " << buffer.getSize() << "b\n";
  259. char* message = new char[buffer.getSize()];
  260. buffer.lese(message, (int)buffer.getSize());
  261. msg->setMessage(message, (int)buffer.getSize());
  262. msg->setUseBackground();
  263. Entity* e = Game::INSTANCE->zEntity(id);
  264. if (e)
  265. {
  266. Punkt p = location;
  267. int dimId = dimensionId;
  268. msg->setOnAfterSend([this, p, dimId, observer]() {
  269. // check if chunk is still loaded
  270. if (Game::INSTANCE->zDimension(dimId)
  271. && Game::INSTANCE->zDimension(dimId)->zChunk(p) == this)
  272. {
  273. // send all waiting messages to the observer
  274. observer->setReady();
  275. }
  276. });
  277. Game::INSTANCE->sendMessage(msg, e);
  278. }
  279. else
  280. msg->release();
  281. });
  282. }
  283. void Chunk::removeObserver(Entity* zEntity)
  284. {
  285. int index = 0;
  286. for (InformationObserver* observer : observers)
  287. {
  288. if (observer->getEntityId() == zEntity->getId())
  289. {
  290. observers.remove(index);
  291. return;
  292. }
  293. index++;
  294. }
  295. }
  296. void Chunk::api(Framework::StreamReader* zRequest,
  297. Entity* zSource,
  298. DoLaterHandler& laterHandler)
  299. {
  300. char type;
  301. zRequest->lese(&type, 1);
  302. switch (type)
  303. {
  304. case 0:
  305. // register observer
  306. addObserver(zSource, laterHandler);
  307. break;
  308. case 1:
  309. // unsubscribe
  310. removeObserver(zSource);
  311. break;
  312. }
  313. }
  314. void Chunk::initializeLightning()
  315. {
  316. unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
  317. unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
  318. while (true)
  319. {
  320. bool changes = false;
  321. for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
  322. {
  323. for (int x = 0; x < CHUNK_SIZE; x++)
  324. {
  325. for (int y = 0; y < CHUNK_SIZE; y++)
  326. {
  327. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  328. unsigned char* light = getLightData(Vec3<int>(x, y, z));
  329. unsigned char newLight[6] = {0, 0, 0, 0, 0, 0};
  330. for (int i = 0; i < 6; i++)
  331. {
  332. unsigned char* neighborLeight;
  333. Vec3<int> neighborPos
  334. = Vec3<int>(x, y, z)
  335. + getDirection(getDirectionFromIndex(i));
  336. if (neighborPos.z < 0 || neighborPos.x < 0
  337. || neighborPos.y < 0 || neighborPos.x >= CHUNK_SIZE
  338. || neighborPos.y >= CHUNK_SIZE)
  339. {
  340. neighborLeight = noLight;
  341. }
  342. else if (neighborPos.z >= WORLD_HEIGHT)
  343. {
  344. neighborLeight = dayLight;
  345. }
  346. else
  347. {
  348. neighborLeight = getLightData(neighborPos);
  349. }
  350. for (int j = 0; j < 3; j++)
  351. newLight[j] = (unsigned char)MAX(newLight[j],
  352. i == getDirectionIndex(TOP)
  353. ? neighborLeight[j]
  354. : (unsigned char)((float)neighborLeight[j]
  355. * 0.8f));
  356. for (int j = 3; j < 6; j++)
  357. newLight[j] = (unsigned char)MAX(newLight[j],
  358. (unsigned char)((float)neighborLeight[j]
  359. * 0.85f));
  360. }
  361. const Block* current
  362. = blocks[index] ? blocks[index]
  363. : StaticRegistry<BlockType>::INSTANCE
  364. .zElement(blockIds[index])
  365. ->zDefault();
  366. // add own light emission
  367. for (int j = 3; j < 6; j++)
  368. newLight[j] = (unsigned char)MAX(newLight[j],
  369. current->getLightEmisionColor()[j - 3]);
  370. current->filterPassingLight(newLight);
  371. current->filterPassingLight(newLight + 3);
  372. for (int i = 0; i < 6; i++)
  373. {
  374. if (newLight[i] != light[i])
  375. {
  376. changes = 1;
  377. memcpy(light, newLight, 6);
  378. break;
  379. }
  380. }
  381. }
  382. }
  383. }
  384. if (!changes) break;
  385. }
  386. }
  387. Framework::Either<Block*, int> Chunk::zBlockAt(
  388. Framework::Vec3<int> location) const
  389. {
  390. int index = Chunk::index(location);
  391. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
  392. if (blocks[index])
  393. return blocks[index];
  394. else
  395. return (int)blockIds[index];
  396. }
  397. const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
  398. {
  399. auto b = zBlockAt(location);
  400. if (b.isA()) return b;
  401. return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->zDefault();
  402. }
  403. void Chunk::instantiateBlock(Framework::Vec3<int> location)
  404. {
  405. auto b = zBlockAt(location);
  406. if (b.isA()) return;
  407. if (!b.getB()) generateBlock(location);
  408. b = zBlockAt(location);
  409. if (b.isB())
  410. putBlockAt(location,
  411. StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())
  412. ->createBlockAt(
  413. {location.x + this->location.x - CHUNK_SIZE / 2,
  414. location.y + this->location.y - CHUNK_SIZE / 2,
  415. location.z},
  416. dimensionId,
  417. 0));
  418. }
  419. void Chunk::generateBlock(Framework::Vec3<int> location)
  420. {
  421. int index = Chunk::index(location);
  422. if (blockIds[index]) return;
  423. auto generated = Game::INSTANCE->zGenerator()->generateSingleBlock(
  424. {location.x + this->location.x - CHUNK_SIZE / 2,
  425. location.y + this->location.y - CHUNK_SIZE / 2,
  426. location.z},
  427. dimensionId);
  428. if (generated.isA())
  429. putBlockAt(location, generated);
  430. else
  431. putBlockTypeAt(location, generated);
  432. }
  433. void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
  434. {
  435. int index = Chunk::index(location);
  436. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT && index >= 0);
  437. Block* old = blocks[index];
  438. if (old && old->isTickSource())
  439. { // remove from tick sorces
  440. for (Framework::Iterator<Block*> obj = tickSources.begin(); obj; obj++)
  441. {
  442. if (obj.val() == old)
  443. {
  444. obj.remove();
  445. break;
  446. }
  447. }
  448. }
  449. bool change = 0;
  450. bool wasLightSource
  451. = old ? old->zBlockType()->isLightSource()
  452. : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])
  453. ->isLightSource();
  454. bool isLightSource = 0;
  455. if (block)
  456. {
  457. change
  458. = blockIds[index] != (unsigned short)block->zBlockType()->getId();
  459. blockIds[index] = (unsigned short)block->zBlockType()->getId();
  460. isLightSource = block->zBlockType()->isLightSource();
  461. }
  462. else
  463. {
  464. if (old != 0)
  465. {
  466. blockIds[index] = BlockTypeEnum::NO_BLOCK;
  467. }
  468. change = old != 0;
  469. }
  470. blocks[index] = block;
  471. for (int i = 0; i < 6; i++)
  472. {
  473. Direction d = getDirectionFromIndex(i);
  474. Either<Block*, int> neighbor
  475. = zBlockNeighbor(location + getDirection(d));
  476. if (neighbor.isA())
  477. {
  478. if (block)
  479. {
  480. ((Block*)neighbor)
  481. ->setNeighbour(getOppositeDirection(d), block);
  482. }
  483. else
  484. {
  485. ((Block*)neighbor)
  486. ->setNeighbour(getOppositeDirection(d), blockIds[index]);
  487. }
  488. }
  489. if (block) block->setNeighbour(d, neighbor);
  490. }
  491. if (old) old->release();
  492. if (block && block->isTickSource())
  493. { // add to tick sources
  494. tickSources.add(block);
  495. }
  496. if (change)
  497. {
  498. if (isLightSource != wasLightSource)
  499. {
  500. if (isLightSource)
  501. addLightSource(index);
  502. else
  503. removeLightSource(index);
  504. }
  505. if (added)
  506. {
  507. sendBlockInfo(location);
  508. if (block)
  509. {
  510. Game::INSTANCE->updateLightningWithoutWait(getDimensionId(),
  511. Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2,
  512. location.y + this->location.y - CHUNK_SIZE / 2,
  513. location.z));
  514. }
  515. }
  516. }
  517. if (added)
  518. {
  519. Game::INSTANCE->zDimension(dimensionId)
  520. ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
  521. location.y + this->location.y - CHUNK_SIZE / 2,
  522. location.z);
  523. }
  524. }
  525. void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
  526. {
  527. int index = Chunk::index(location);
  528. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
  529. bool wasLightSource
  530. = StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])
  531. ->isLightSource();
  532. bool isLightSource
  533. = StaticRegistry<BlockType>::INSTANCE.zElement(type)->isLightSource();
  534. if (blockIds[index] != (unsigned short)type)
  535. {
  536. blockIds[index] = (unsigned short)type;
  537. for (int i = 0; i < 6; i++)
  538. {
  539. Direction d = getDirectionFromIndex(i);
  540. Either<Block*, int> neighbor
  541. = zBlockNeighbor(location + getDirection(d));
  542. if (neighbor.isA())
  543. ((Block*)neighbor)
  544. ->setNeighbourType(getOppositeDirection(d), type);
  545. }
  546. if (isLightSource != wasLightSource)
  547. {
  548. if (isLightSource)
  549. addLightSource(index);
  550. else
  551. removeLightSource(index);
  552. }
  553. if (added)
  554. {
  555. sendBlockInfo(location);
  556. Game::INSTANCE->updateLightningWithoutWait(getDimensionId(),
  557. Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2,
  558. location.y + this->location.y - CHUNK_SIZE / 2,
  559. location.z));
  560. Game::INSTANCE->zDimension(dimensionId)
  561. ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
  562. location.y + this->location.y - CHUNK_SIZE / 2,
  563. location.z);
  564. }
  565. }
  566. }
  567. void Chunk::sendBlockInfo(Framework::Vec3<int> location)
  568. {
  569. int index = Chunk::index(location);
  570. char* msg = new char[9];
  571. msg[0] = 0; // set block
  572. *(int*)(msg + 1) = index;
  573. *(int*)(msg + 5) = blockIds[index];
  574. NetworkMessage* message = new NetworkMessage();
  575. message->addressChunck(this);
  576. message->setMessage(msg, 9);
  577. notifyObservers(message);
  578. for (int i = 0; i < 6; i++)
  579. {
  580. Direction d = getDirectionFromIndex(i);
  581. Framework::Vec3<int> loc = location + getDirection(d);
  582. if (loc.x >= 0 && loc.x < CHUNK_SIZE && loc.y >= 0 && loc.y < CHUNK_SIZE
  583. && loc.z >= 0 && loc.z < WORLD_HEIGHT)
  584. {
  585. broadcastLightData(Chunk::index(loc), true);
  586. }
  587. else if (loc.z >= 0 && loc.z < WORLD_HEIGHT && i < 4 && zNeighbours[i])
  588. {
  589. NetworkMessage* msg = new NetworkMessage();
  590. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  591. char* message = new char[19];
  592. message[0] = 5;
  593. *(int*)(message + 1) = loc.x + this->location.x - CHUNK_SIZE / 2;
  594. *(int*)(message + 5) = loc.y + this->location.y - CHUNK_SIZE / 2;
  595. *(int*)(message + 9) = loc.z;
  596. loc -= getDirection(d) * CHUNK_SIZE;
  597. memcpy(message + 13, zNeighbours[i]->getLightData(loc), 6);
  598. msg->setMessage(message, 19);
  599. notifyObservers(msg);
  600. }
  601. }
  602. }
  603. void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
  604. {
  605. zNeighbours[getDirectionIndex(dir)] = zChunk;
  606. for (int i = 0; i < CHUNK_SIZE; i++)
  607. {
  608. for (int z = 0; z < WORLD_HEIGHT; z++)
  609. {
  610. int index = 0;
  611. int j = 0;
  612. if (dir == NORTH)
  613. {
  614. index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  615. j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  616. }
  617. else if (dir == EAST)
  618. {
  619. index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  620. j = i * WORLD_HEIGHT + z;
  621. }
  622. else if (dir == SOUTH)
  623. {
  624. index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  625. j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  626. }
  627. else if (dir == WEST)
  628. {
  629. index = i * WORLD_HEIGHT + z;
  630. j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  631. }
  632. if (blocks[index])
  633. {
  634. if (zChunk && zChunk->blocks[j])
  635. blocks[index]->setNeighbour(dir, zChunk->blocks[j]);
  636. else
  637. {
  638. blocks[index]->setNeighbour(dir, 0);
  639. blocks[index]->setNeighbourType(
  640. dir, zChunk ? zChunk->blockIds[j] : 0);
  641. }
  642. }
  643. if (zChunk)
  644. {
  645. if (!blocks[index])
  646. {
  647. if (zChunk->blockIds[j] == BlockTypeEnum::AIR
  648. && !blockIds[index])
  649. {
  650. generateBlock(
  651. Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE,
  652. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  653. index % WORLD_HEIGHT));
  654. }
  655. }
  656. if (blockIds[index] != BlockTypeEnum::AIR
  657. && blockIds[index] != BlockTypeEnum::NO_BLOCK)
  658. {
  659. zChunk->broadcastLightData(j, true);
  660. }
  661. }
  662. }
  663. }
  664. }
  665. void Chunk::load(Framework::StreamReader* zReader)
  666. {
  667. for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
  668. {
  669. unsigned short blockType;
  670. zReader->lese((char*)&blockType, 2);
  671. if (blockType)
  672. {
  673. Framework::Vec3<int> pos
  674. = Framework::Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE,
  675. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  676. index % WORLD_HEIGHT);
  677. bool d;
  678. zReader->lese((char*)&d, 1);
  679. if (d)
  680. {
  681. putBlockAt(pos,
  682. StaticRegistry<BlockType>::INSTANCE.zElement(blockType)
  683. ->loadBlock(Framework::Vec3<int>(
  684. pos.x + location.x - CHUNK_SIZE / 2,
  685. pos.y + location.y - CHUNK_SIZE / 2,
  686. pos.z),
  687. zReader,
  688. dimensionId));
  689. }
  690. else
  691. {
  692. putBlockTypeAt(pos, blockType);
  693. }
  694. }
  695. }
  696. initializeLightning();
  697. }
  698. void Chunk::save(Framework::StreamWriter* zWriter)
  699. {
  700. for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
  701. {
  702. unsigned short blockType
  703. = blocks[index]
  704. ? (unsigned short)blocks[index]->zBlockType()->getId()
  705. : blockIds[index];
  706. zWriter->schreibe((char*)&blockType, 2);
  707. if (blockType)
  708. {
  709. if (blocks[index])
  710. {
  711. bool d = 1;
  712. zWriter->schreibe((char*)&d, 1);
  713. StaticRegistry<BlockType>::INSTANCE.zElement(blockType)
  714. ->saveBlock(blocks[index], zWriter);
  715. }
  716. else
  717. {
  718. bool d = 0;
  719. zWriter->schreibe((char*)&d, 1);
  720. }
  721. }
  722. }
  723. }
  724. void Chunk::sendToClient(Framework::StreamWriter* zWriter)
  725. {
  726. for (int x = 0; x < CHUNK_SIZE; x++)
  727. {
  728. for (int y = 0; y < CHUNK_SIZE; y++)
  729. {
  730. for (int z = 0; z < WORLD_HEIGHT; z++)
  731. {
  732. int index = Chunk::index({x, y, z});
  733. unsigned short blockType
  734. = blocks[index]
  735. ? (unsigned short)blocks[index]->zBlockType()->getId()
  736. : blockIds[index];
  737. if (blockType)
  738. {
  739. bool visible = 0;
  740. if (!visible)
  741. {
  742. if (!blocks[index])
  743. {
  744. if (CONST_BLOCK(0, blockIds[index])->isTransparent()
  745. || CONST_BLOCK(0, blockIds[index])
  746. ->isPassable())
  747. visible = 1;
  748. else
  749. {
  750. for (int d = 0; d < 6 && !visible; d++)
  751. {
  752. Vec3<int> pos
  753. = getDirection(
  754. (Directions)getDirectionFromIndex(
  755. d))
  756. + Framework::Vec3<int>(x, y, z);
  757. auto n = zBlockNeighbor(pos);
  758. if (n.isA()
  759. && (((Block*)n)->isPassable()
  760. || ((Block*)n)->isTransparent()))
  761. visible = 1;
  762. if (n.isB()
  763. && (CONST_BLOCK(0, n)->isTransparent()
  764. || CONST_BLOCK(0, n)->isPassable()))
  765. visible = 1;
  766. if (pos.x < 0 || pos.y < 0 || pos.z < 0
  767. || pos.x >= CHUNK_SIZE
  768. || pos.y >= CHUNK_SIZE
  769. || pos.z >= WORLD_HEIGHT)
  770. visible = 1;
  771. }
  772. }
  773. }
  774. else
  775. visible = blocks[index]->isVisible();
  776. }
  777. if (visible
  778. && (blocks[index] || blockType != BlockTypeEnum::AIR))
  779. {
  780. zWriter->schreibe((char*)&blockType, 2);
  781. zWriter->schreibe((char*)&index, 4);
  782. }
  783. }
  784. }
  785. }
  786. }
  787. unsigned short end = 0;
  788. zWriter->schreibe((char*)&end, 2);
  789. }
  790. void Chunk::removeUnusedBlocks()
  791. {
  792. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  793. {
  794. if (!blocks[i] && blockIds[i])
  795. {
  796. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  797. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  798. int z = i % WORLD_HEIGHT;
  799. bool visible = 0;
  800. if (CONST_BLOCK(0, blockIds[i])->isTransparent()
  801. || CONST_BLOCK(0, blockIds[i])->isPassable())
  802. visible = 1;
  803. else
  804. {
  805. for (int d = 0; d < 6 && !visible; d++)
  806. {
  807. auto n = zBlockNeighbor(
  808. getDirection((Directions)getDirectionFromIndex(d))
  809. + Framework::Vec3<int>(x, y, z));
  810. if (n.isA()
  811. && (((Block*)n)->isPassable()
  812. || ((Block*)n)->isTransparent()))
  813. visible = 1;
  814. if (n.isB()
  815. && (CONST_BLOCK(0, n)->isTransparent()
  816. || CONST_BLOCK(0, n)->isPassable()))
  817. visible = 1;
  818. }
  819. }
  820. if (!visible)
  821. {
  822. putBlockAt({x, y, z}, 0);
  823. putBlockTypeAt({x, y, z}, 0);
  824. }
  825. }
  826. }
  827. int count = 0;
  828. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  829. {
  830. if (blockIds[i] && blockIds[i] != BlockTypeEnum::AIR) count++;
  831. }
  832. std::cout << "chunk " << location.x << ", " << location.y
  833. << " was generated with " << count << " blocks.\n";
  834. }
  835. int Chunk::getDimensionId() const
  836. {
  837. return dimensionId;
  838. }
  839. void Chunk::onLoaded()
  840. {
  841. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  842. {
  843. if (blocks[i]) blocks[i]->onLoaded();
  844. }
  845. currentlyLoading = 0;
  846. }
  847. void Chunk::onUnloaded()
  848. {
  849. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  850. {
  851. if (blocks[i]) blocks[i]->onUnloaded();
  852. }
  853. }
  854. Framework::Punkt Chunk::getCenter() const
  855. {
  856. return location;
  857. }
  858. Framework::Vec3<int> Chunk::getMin() const
  859. {
  860. return {location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0};
  861. }
  862. Framework::Vec3<int> Chunk::getMax() const
  863. {
  864. return {
  865. location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT};
  866. }
  867. void Chunk::prepareRemove()
  868. {
  869. added = 0;
  870. for (int i = 0; i < 4; i++)
  871. {
  872. if (zNeighbours[i])
  873. {
  874. zNeighbours[i]->setNeighbor(
  875. getOppositeDirection(getDirectionFromIndex(i)), 0);
  876. zNeighbours[i] = 0;
  877. }
  878. }
  879. }
  880. void Chunk::setAdded()
  881. {
  882. added = 1;
  883. }
  884. bool Chunk::hasObservers() const
  885. {
  886. return observers.getEintragAnzahl() > 0 || currentlyLoading;
  887. }
  888. unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
  889. {
  890. int index = Chunk::index(location) * 6;
  891. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
  892. return lightData + index;
  893. }
  894. void Chunk::setLightData(
  895. Framework::Vec3<int> location, unsigned char* data, bool foreground)
  896. {
  897. int index = Chunk::index(location);
  898. memcpy(lightData + index * 6, data, 6);
  899. // check if neighbor is a visible block and send update to clients
  900. bool needSend = 0;
  901. for (int i = 0; i < 6; i++)
  902. {
  903. Vec3<int> pos = location + getDirection(getDirectionFromIndex(i));
  904. if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
  905. {
  906. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
  907. && pos.y < CHUNK_SIZE)
  908. {
  909. int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
  910. int type = blockIds[bi];
  911. needSend |= type != BlockTypeEnum::NO_BLOCK
  912. && type != BlockTypeEnum::AIR;
  913. if (needSend) break;
  914. }
  915. else
  916. {
  917. needSend = 1; // TODO: check if the block is visible
  918. }
  919. }
  920. }
  921. if (needSend)
  922. {
  923. broadcastLightData(index, foreground);
  924. }
  925. }
  926. int Chunk::getBlockTypeAt(Framework::Vec3<int> location) const
  927. {
  928. return blockIds[index(location)];
  929. }