Chunk.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324
  1. #include "Chunk.h"
  2. #include <AsynchronCall.h>
  3. #include <InMemoryBuffer.h>
  4. #include <Logging.h>
  5. #include "Constants.h"
  6. #include "Dimension.h"
  7. #include "Entity.h"
  8. #include "FluidBlock.h"
  9. #include "Game.h"
  10. #include "NoBlock.h"
  11. #include "WorldGenerator.h"
  12. Chunk::Chunk(Framework::Punkt location, int dimensionId)
  13. : ReferenceCounter(),
  14. dimensionId(dimensionId),
  15. location(location),
  16. added(0),
  17. worldUpdated(1),
  18. currentlyLoading(1)
  19. {
  20. blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  21. blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  22. lightData = new unsigned char[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6];
  23. memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
  24. memset(blockIds,
  25. 0,
  26. CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
  27. memset(lightData, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
  28. zNeighbours[0] = 0;
  29. zNeighbours[1] = 0;
  30. zNeighbours[2] = 0;
  31. zNeighbours[3] = 0;
  32. }
  33. Chunk::Chunk(Framework::Punkt location,
  34. int dimensionId,
  35. Framework::StreamReader* zReader)
  36. : Chunk(location, dimensionId)
  37. {
  38. load(zReader);
  39. }
  40. Chunk::~Chunk()
  41. {
  42. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  43. {
  44. if (blocks[i]) blocks[i]->release();
  45. }
  46. delete[] blocks;
  47. delete[] blockIds;
  48. delete[] lightData;
  49. }
  50. void Chunk::lock()
  51. {
  52. cs.lock();
  53. }
  54. void Chunk::unlock()
  55. {
  56. cs.unlock();
  57. }
  58. void Chunk::tick(TickQueue* zQueue)
  59. {
  60. for (Block* source : tickSourcesEachTick)
  61. zQueue->addToQueue(source);
  62. if (worldUpdated)
  63. {
  64. worldUpdated = 0;
  65. for (Block* source : tickSourcesAfterUpdate)
  66. {
  67. if (source->needsTick())
  68. {
  69. zQueue->addToQueue(source);
  70. worldUpdated = 1;
  71. }
  72. }
  73. }
  74. }
  75. void Chunk::postTick() {}
  76. void Chunk::addLightSource(int index)
  77. {
  78. for (int i : lightSources)
  79. {
  80. if (i == index) return;
  81. }
  82. lightSources.add(index);
  83. }
  84. void Chunk::removeLightSource(int index)
  85. {
  86. for (auto i = lightSources.begin(); i; i++)
  87. {
  88. if (i.val() == index)
  89. {
  90. i.remove();
  91. return;
  92. }
  93. }
  94. }
  95. void Chunk::sendToClient(Framework::StreamWriter* zWriter, bool* instanceMap)
  96. {
  97. for (int x = 0; x < CHUNK_SIZE; x++)
  98. {
  99. for (int y = 0; y < CHUNK_SIZE; y++)
  100. {
  101. for (int z = 0; z < WORLD_HEIGHT; z++)
  102. {
  103. int index = Chunk::index({x, y, z});
  104. const BlockType* type
  105. = Game::INSTANCE->zBlockType(blockIds[index]);
  106. if (isVisible(index) && type->doesNeedClientInstance())
  107. {
  108. if (z > 0 && z < WORLD_HEIGHT - 1)
  109. {
  110. instanceMap[index + (CHUNK_SIZE + 1) * WORLD_HEIGHT + 1]
  111. = 1;
  112. instanceMap[index + (CHUNK_SIZE + 1) * WORLD_HEIGHT - 1]
  113. = 1;
  114. }
  115. instanceMap[index + WORLD_HEIGHT] = 1;
  116. instanceMap[index + (2 * CHUNK_SIZE + 1) * WORLD_HEIGHT]
  117. = 1;
  118. instanceMap[index + CHUNK_SIZE * WORLD_HEIGHT] = 1;
  119. instanceMap[index + (CHUNK_SIZE + 2) * WORLD_HEIGHT] = 1;
  120. zWriter->schreibe((char*)&blockIds[index], 2);
  121. zWriter->schreibe((char*)&index, 4);
  122. char state = 0;
  123. if (type->isFluid())
  124. {
  125. state |= 1;
  126. }
  127. if ((blocks[index] && blocks[index]->isPassable())
  128. || (type->zDefault()->isPassable()))
  129. {
  130. state |= 2;
  131. }
  132. zWriter->schreibe((char*)&state, 1);
  133. if ((state | 1) == state)
  134. {
  135. FluidBlock* fluidBlock
  136. = dynamic_cast<FluidBlock*>(blocks[index]);
  137. char data
  138. = fluidBlock ? fluidBlock->getFlowOptions() : 0;
  139. zWriter->schreibe(&data, 1);
  140. data = fluidBlock ? fluidBlock->getDistanceToSource()
  141. : 0;
  142. zWriter->schreibe(&data, 1);
  143. }
  144. if ((state | 2) == state)
  145. {
  146. float speedModifier
  147. = blocks[index]
  148. ? blocks[index]->getSpeedModifier()
  149. : type->zDefault()->getSpeedModifier();
  150. zWriter->schreibe((char*)&speedModifier, 4);
  151. }
  152. }
  153. }
  154. }
  155. }
  156. unsigned short end = 0;
  157. zWriter->schreibe((char*)&end, 2);
  158. }
  159. void Chunk::sendLightToClient(
  160. Framework::StreamWriter* zWriter, bool* instanceMap)
  161. {
  162. cs.lock();
  163. Chunk* zNeighbours[4];
  164. for (int i = 0; i < 4; i++)
  165. {
  166. zNeighbours[i]
  167. = this->zNeighbours[i]
  168. ? dynamic_cast<Chunk*>(this->zNeighbours[i]->getThis())
  169. : 0;
  170. if (zNeighbours[i])
  171. {
  172. Direction dir = getDirectionFromIndex(i);
  173. switch (dir)
  174. {
  175. case WEST:
  176. for (int z = 0; z < WORLD_HEIGHT; z++)
  177. {
  178. for (int j = 0; j < CHUNK_SIZE; j++)
  179. {
  180. int type = zNeighbours[i]->getBlockTypeAt(
  181. {CHUNK_SIZE - 1, j, z});
  182. if (type
  183. && Game::INSTANCE->zBlockType(type)
  184. ->doesNeedClientInstance())
  185. {
  186. instanceMap[(CHUNK_SIZE + j + 1) * WORLD_HEIGHT + z]
  187. = 1;
  188. }
  189. }
  190. }
  191. break;
  192. case NORTH:
  193. for (int z = 0; z < WORLD_HEIGHT; z++)
  194. {
  195. for (int j = 0; j < CHUNK_SIZE; j++)
  196. {
  197. int type = zNeighbours[i]->getBlockTypeAt(
  198. {j, CHUNK_SIZE - 1, z});
  199. if (type
  200. && Game::INSTANCE->zBlockType(type)
  201. ->doesNeedClientInstance())
  202. {
  203. instanceMap[((j + 1) * CHUNK_SIZE + 1)
  204. * WORLD_HEIGHT
  205. + z]
  206. = 1;
  207. }
  208. }
  209. }
  210. break;
  211. case EAST:
  212. for (int z = 0; z < WORLD_HEIGHT; z++)
  213. {
  214. for (int j = 0; j < CHUNK_SIZE; j++)
  215. {
  216. int type = zNeighbours[i]->getBlockTypeAt({0, j, z});
  217. if (type
  218. && Game::INSTANCE->zBlockType(type)
  219. ->doesNeedClientInstance())
  220. {
  221. instanceMap[((CHUNK_SIZE)*CHUNK_SIZE + j + 1)
  222. * WORLD_HEIGHT
  223. + z]
  224. = 1;
  225. }
  226. }
  227. }
  228. break;
  229. case SOUTH:
  230. for (int z = 0; z < WORLD_HEIGHT; z++)
  231. {
  232. for (int j = 0; j < CHUNK_SIZE; j++)
  233. {
  234. int type = zNeighbours[i]->getBlockTypeAt({j, 0, z});
  235. if (type
  236. && Game::INSTANCE->zBlockType(type)
  237. ->doesNeedClientInstance())
  238. {
  239. instanceMap[((j + 1) * CHUNK_SIZE + CHUNK_SIZE)
  240. * WORLD_HEIGHT
  241. + z]
  242. = 1;
  243. }
  244. }
  245. }
  246. break;
  247. }
  248. }
  249. }
  250. cs.unlock();
  251. for (int z = 0; z < WORLD_HEIGHT; z++)
  252. {
  253. for (int x = -1; x <= CHUNK_SIZE; x++)
  254. {
  255. for (int y = -1; y <= CHUNK_SIZE; y++)
  256. {
  257. if ((x < 0 || x == CHUNK_SIZE) && (y < 0 || y > CHUNK_SIZE))
  258. {
  259. continue;
  260. }
  261. if (instanceMap[((x + 1) * CHUNK_SIZE + y + 1) * WORLD_HEIGHT
  262. + z])
  263. {
  264. if (x >= 0 && x < CHUNK_SIZE && y >= 0 && y < CHUNK_SIZE)
  265. {
  266. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  267. zWriter->schreibe((char*)&index, 4);
  268. zWriter->schreibe((char*)(lightData + index * 6), 6);
  269. }
  270. else
  271. {
  272. int dir;
  273. int index = 0;
  274. if (x == -1)
  275. {
  276. dir = getDirectionIndex(WEST);
  277. index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y)
  278. * WORLD_HEIGHT
  279. + z;
  280. }
  281. else if (y == -1)
  282. {
  283. dir = getDirectionIndex(NORTH);
  284. index = (x * CHUNK_SIZE + CHUNK_SIZE - 1)
  285. * WORLD_HEIGHT
  286. + z;
  287. }
  288. else if (x == CHUNK_SIZE)
  289. {
  290. dir = getDirectionIndex(EAST);
  291. index = y * WORLD_HEIGHT + z;
  292. }
  293. else if (y == CHUNK_SIZE)
  294. {
  295. dir = getDirectionIndex(SOUTH);
  296. index = (x * CHUNK_SIZE) * WORLD_HEIGHT + z;
  297. }
  298. if (zNeighbours[dir])
  299. {
  300. int i = -1;
  301. zWriter->schreibe((char*)&i, 4);
  302. zWriter->schreibe((char*)&x, 4);
  303. zWriter->schreibe((char*)&y, 4);
  304. zWriter->schreibe((char*)&z, 4);
  305. zWriter->schreibe(
  306. (char*)(zNeighbours[dir]->lightData
  307. + index * 6),
  308. 6);
  309. }
  310. }
  311. }
  312. }
  313. }
  314. }
  315. int end = -2;
  316. zWriter->schreibe((char*)&end, 4);
  317. for (int i = 0; i < 4; i++)
  318. {
  319. if (zNeighbours[i])
  320. {
  321. zNeighbours[i]->release();
  322. }
  323. }
  324. }
  325. bool Chunk::isVisible(int index) const
  326. {
  327. unsigned short blockType
  328. = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId()
  329. : blockIds[index];
  330. if (blockType)
  331. {
  332. if (CONST_BLOCK(0, blockIds[index])->isTransparent()
  333. || CONST_BLOCK(0, blockIds[index])->isPassable())
  334. return 1;
  335. else
  336. {
  337. Framework::Vec3<int> indexPos
  338. = {(index / WORLD_HEIGHT) / CHUNK_SIZE,
  339. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  340. index % WORLD_HEIGHT};
  341. for (int d = 0; d < 6; d++)
  342. {
  343. Framework::Either<Block*, int> n = BlockTypeEnum::NO_BLOCK;
  344. Framework::Vec3<int> pos
  345. = getDirection((Directions)getDirectionFromIndex(d))
  346. + indexPos;
  347. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
  348. && pos.y < CHUNK_SIZE && pos.z >= 0 && pos.z < WORLD_HEIGHT)
  349. {
  350. n = zBlockAt(pos);
  351. }
  352. else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
  353. && zNeighbours[d])
  354. {
  355. if (pos.x < 0) pos.x += CHUNK_SIZE;
  356. if (pos.x >= CHUNK_SIZE) pos.x -= CHUNK_SIZE;
  357. if (pos.y < 0) pos.y += CHUNK_SIZE;
  358. if (pos.y >= CHUNK_SIZE) pos.y -= CHUNK_SIZE;
  359. n = zNeighbours[d]->zBlockAt(pos);
  360. }
  361. else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
  362. && !zNeighbours[d])
  363. {
  364. return 1;
  365. }
  366. if (n.isA()
  367. && (((Block*)n)->isPassable()
  368. || ((Block*)n)->isTransparent()))
  369. return 1;
  370. if (n.isB()
  371. && (CONST_BLOCK(0, n)->isTransparent()
  372. || CONST_BLOCK(0, n)->isPassable()))
  373. return 1;
  374. }
  375. }
  376. }
  377. return 0;
  378. }
  379. void Chunk::broadcastLightData(int index, bool foreground)
  380. {
  381. int x = (index / WORLD_HEIGHT) / CHUNK_SIZE;
  382. int y = (index / WORLD_HEIGHT) % CHUNK_SIZE;
  383. int z = index % WORLD_HEIGHT;
  384. NetworkMessage* msg = new NetworkMessage();
  385. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  386. char* message = new char[19];
  387. message[0] = 5;
  388. *(int*)(message + 1) = x + this->location.x - CHUNK_SIZE / 2;
  389. *(int*)(message + 5) = y + this->location.y - CHUNK_SIZE / 2;
  390. *(int*)(message + 9) = z;
  391. memcpy(message + 13, lightData + index * 6, 6);
  392. msg->setMessage(message, 19);
  393. if (!foreground) msg->setUseBackground();
  394. notifyObservers(msg);
  395. }
  396. Framework::Either<Block*, int> Chunk::zBlockNeighbor(
  397. Framework::Vec3<int> location, OUT Chunk** zNeighborChunk)
  398. {
  399. if (location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0
  400. && location.y < CHUNK_SIZE && location.z >= 0
  401. && location.z < WORLD_HEIGHT)
  402. {
  403. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT
  404. + location.z;
  405. if (zNeighborChunk)
  406. {
  407. *zNeighborChunk = this;
  408. }
  409. if (blocks[index])
  410. return blocks[index];
  411. else
  412. return (int)blockIds[index];
  413. }
  414. if (location.z >= 0 && location.z < WORLD_HEIGHT)
  415. return Game::INSTANCE->zBlockAt(
  416. {location.x + this->location.x - CHUNK_SIZE / 2,
  417. location.y + this->location.y - CHUNK_SIZE / 2,
  418. location.z},
  419. dimensionId,
  420. zNeighborChunk);
  421. return 0;
  422. }
  423. void Chunk::notifyObservers(NetworkMessage* msg)
  424. {
  425. Framework::Array<int> remove;
  426. int index = 0;
  427. for (InformationObserver* observer : observers)
  428. {
  429. if (!observer->sendMessage(
  430. dynamic_cast<NetworkMessage*>(msg->getThis())))
  431. {
  432. remove.add(index, 0);
  433. }
  434. index++;
  435. }
  436. for (int i : remove)
  437. observers.remove(i);
  438. msg->release();
  439. }
  440. void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
  441. {
  442. for (InformationObserver* observer : observers)
  443. {
  444. if (observer->getEntityId() == zEntity->getId()) return;
  445. }
  446. int id = zEntity->getId();
  447. observers.add(new InformationObserver(id));
  448. laterHandler.addTodo([this, id]() {
  449. Framework::InMemoryBuffer buffer;
  450. buffer.schreibe("\4", 1);
  451. buffer.schreibe((char*)&location.x, 4);
  452. buffer.schreibe((char*)&location.y, 4);
  453. bool instanceMap[(CHUNK_SIZE + 2) * (CHUNK_SIZE + 2) * WORLD_HEIGHT];
  454. memset(instanceMap, 0, sizeof(instanceMap));
  455. sendToClient(&buffer, instanceMap);
  456. sendLightToClient(&buffer, instanceMap);
  457. NetworkMessage* msg = new NetworkMessage();
  458. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  459. #ifdef _DEBUG
  460. Framework::Logging::debug()
  461. << "chunk size: " << location.x << ", " << location.y << ": "
  462. << buffer.getSize() << "b";
  463. #endif
  464. char* message = new char[buffer.getSize()];
  465. buffer.lese(message, (int)buffer.getSize());
  466. msg->setMessage(message, (int)buffer.getSize());
  467. msg->setUseBackground();
  468. Entity* e = Game::INSTANCE->zEntity(id);
  469. if (e)
  470. {
  471. Game::INSTANCE->sendMessage(msg, e);
  472. }
  473. else
  474. msg->release();
  475. });
  476. }
  477. void Chunk::removeObserver(Entity* zEntity)
  478. {
  479. int index = 0;
  480. for (InformationObserver* observer : observers)
  481. {
  482. if (observer->getEntityId() == zEntity->getId())
  483. {
  484. observers.remove(index);
  485. return;
  486. }
  487. index++;
  488. }
  489. }
  490. void Chunk::api(Framework::StreamReader* zRequest,
  491. Entity* zSource,
  492. DoLaterHandler& laterHandler)
  493. {
  494. char type;
  495. zRequest->lese(&type, 1);
  496. switch (type)
  497. {
  498. case 0:
  499. // register observer
  500. addObserver(zSource, laterHandler);
  501. break;
  502. case 1:
  503. // unsubscribe
  504. removeObserver(zSource);
  505. break;
  506. case 2:
  507. // observer ready
  508. for (InformationObserver* observer : observers)
  509. {
  510. if (observer->getEntityId() == zSource->getId())
  511. {
  512. observer->setReady();
  513. }
  514. }
  515. }
  516. }
  517. void Chunk::initializeLightning()
  518. {
  519. unsigned char dayLight[3] = {255, 255, 255};
  520. unsigned char noLight[3] = {0, 0, 0};
  521. unsigned short visited[CHUNK_SIZE][WORLD_HEIGHT];
  522. memset(visited, 0, sizeof(visited));
  523. int minZ = 0;
  524. int goUps = 0;
  525. for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
  526. {
  527. minZ = z;
  528. unsigned char max[3] = {0, 0, 0};
  529. bool allVisited = 1;
  530. for (int x = 0; x < CHUNK_SIZE; x++)
  531. {
  532. for (int y = 0; y < CHUNK_SIZE; y++)
  533. {
  534. if (visited[y][z] & (1 << x)) continue;
  535. unsigned char* lightAbove
  536. = z == WORLD_HEIGHT - 1
  537. ? dayLight
  538. : getLightData(Framework::Vec3<int>(x, y, z + 1));
  539. if (lightAbove[0] | lightAbove[1] | lightAbove[2])
  540. {
  541. visited[y][z] |= 1 << x;
  542. unsigned char* light
  543. = getLightData(Framework::Vec3<int>(x, y, z));
  544. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  545. const Block* current
  546. = blocks[index]
  547. ? blocks[index]
  548. : Game::INSTANCE->zBlockType(blockIds[index])
  549. ->zDefault();
  550. light[0] = lightAbove[0];
  551. light[1] = lightAbove[1];
  552. light[2] = lightAbove[2];
  553. current->filterPassingLight(light);
  554. max[0] = MAX(max[0], lightAbove[0]);
  555. max[1] = MAX(max[1], lightAbove[1]);
  556. max[2] = MAX(max[2], lightAbove[2]);
  557. }
  558. else
  559. {
  560. allVisited = 0;
  561. }
  562. }
  563. }
  564. if (!(max[0] | max[1] | max[2])) break;
  565. if (!allVisited)
  566. {
  567. bool goUp = 1;
  568. while (goUp)
  569. {
  570. goUp = 0;
  571. bool changes = 1;
  572. while (changes)
  573. {
  574. changes = 0;
  575. for (int x = 0; x < CHUNK_SIZE; x++)
  576. {
  577. for (int y = 0; y < CHUNK_SIZE; y++)
  578. {
  579. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  580. unsigned char* light
  581. = getLightData(Framework::Vec3<int>(x, y, z));
  582. const Block* current
  583. = blocks[index]
  584. ? blocks[index]
  585. : Game::INSTANCE
  586. ->zBlockType(blockIds[index])
  587. ->zDefault();
  588. unsigned char newLight[3] = {0, 0, 0};
  589. for (int i = 0; i < 4; i++)
  590. {
  591. Framework::Vec3<int> neighborPos
  592. = Framework::Vec3<int>(x, y, z)
  593. + getDirection(getDirectionFromIndex(i));
  594. if (neighborPos.x < 0 || neighborPos.y < 0
  595. || neighborPos.x >= CHUNK_SIZE
  596. || neighborPos.y >= CHUNK_SIZE)
  597. {
  598. continue;
  599. }
  600. unsigned char* neighborLeight
  601. = getLightData(neighborPos);
  602. for (int j = 0; j < 3; j++)
  603. {
  604. newLight[j] = (unsigned char)MAX(
  605. newLight[j],
  606. (unsigned char)((float)neighborLeight[j]
  607. * 0.8f));
  608. }
  609. }
  610. current->filterPassingLight(newLight);
  611. if (newLight[0] > light[0] || newLight[1] > light[1]
  612. || newLight[2] > light[2])
  613. {
  614. changes = 1;
  615. light[0] = MAX(light[0], newLight[0]);
  616. light[1] = MAX(light[1], newLight[1]);
  617. light[2] = MAX(light[2], newLight[2]);
  618. if (z < WORLD_HEIGHT - 1
  619. && !(visited[y][z + 1] & (1 << x)))
  620. {
  621. unsigned char* lightAbove = getLightData(
  622. Framework::Vec3<int>(x, y, z + 1));
  623. newLight[0]
  624. = (unsigned char)(light[0] * 0.8f);
  625. newLight[1]
  626. = (unsigned char)(light[1] * 0.8f);
  627. newLight[2]
  628. = (unsigned char)(light[2] * 0.8f);
  629. const Block* above
  630. = blocks[index - 1]
  631. ? blocks[index - 1]
  632. : Game::INSTANCE
  633. ->zBlockType(
  634. blockIds[index - 1])
  635. ->zDefault();
  636. above->filterPassingLight(newLight);
  637. if (newLight[0] > lightAbove[0]
  638. || newLight[1] > lightAbove[1]
  639. || newLight[2] > lightAbove[2])
  640. {
  641. lightAbove[0]
  642. = MAX(lightAbove[0], newLight[0]);
  643. lightAbove[1]
  644. = MAX(lightAbove[1], newLight[1]);
  645. lightAbove[2]
  646. = MAX(lightAbove[2], newLight[2]);
  647. visited[y][z + 1] |= 1 << x;
  648. goUp = 1;
  649. }
  650. }
  651. }
  652. }
  653. }
  654. }
  655. if (goUp)
  656. {
  657. z++;
  658. goUps++;
  659. }
  660. }
  661. }
  662. }
  663. #ifdef _DEBUG
  664. Framework::Logging::debug() << "goUps: " << goUps << " minZ: " << minZ;
  665. #endif
  666. }
  667. void Chunk::updateLightSources()
  668. {
  669. Dimension* zDim = Game::INSTANCE->zDimension(dimensionId);
  670. for (int i : lightSources)
  671. {
  672. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  673. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  674. int z = i % WORLD_HEIGHT;
  675. Framework::Vec3<int> pos = {x, y, z};
  676. zDim->updateLightning(
  677. Framework::Vec3<int>(x + this->location.x - CHUNK_SIZE / 2,
  678. y + this->location.y - CHUNK_SIZE / 2,
  679. z));
  680. }
  681. }
  682. Framework::Either<Block*, int> Chunk::zBlockAt(
  683. Framework::Vec3<int> location) const
  684. {
  685. if (location.z < 0 || location.z >= WORLD_HEIGHT) return 0;
  686. int index = Chunk::index(location);
  687. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
  688. if (blocks[index])
  689. return blocks[index];
  690. else
  691. return (int)blockIds[index];
  692. }
  693. const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
  694. {
  695. auto b = zBlockAt(location);
  696. if (b.isA()) return b;
  697. return Game::INSTANCE->zBlockType(b.getB())->zDefault();
  698. }
  699. const Block* Chunk::zBlockConst(int index) const
  700. {
  701. if (blocks[index])
  702. return blocks[index];
  703. else
  704. return Game::INSTANCE->zBlockType(blockIds[index])->zDefault();
  705. }
  706. void Chunk::instantiateBlock(Framework::Vec3<int> location)
  707. {
  708. auto b = zBlockAt(location);
  709. if (b.isA()) return;
  710. if (!b.getB()) generateBlock(location);
  711. b = zBlockAt(location);
  712. if (b.isB())
  713. putBlockAt(location,
  714. Game::INSTANCE->zBlockType(b.getB())->createBlockAt(
  715. {location.x + this->location.x - CHUNK_SIZE / 2,
  716. location.y + this->location.y - CHUNK_SIZE / 2,
  717. location.z},
  718. dimensionId,
  719. 0));
  720. }
  721. void Chunk::generateBlock(Framework::Vec3<int> location)
  722. {
  723. int index = Chunk::index(location);
  724. if (blockIds[index]) return;
  725. auto generated = Game::INSTANCE->zGenerator()->generateSingleBlock(
  726. {location.x + this->location.x - CHUNK_SIZE / 2,
  727. location.y + this->location.y - CHUNK_SIZE / 2,
  728. location.z},
  729. dimensionId);
  730. if (generated.isA())
  731. putBlockAt(location, generated);
  732. else
  733. putBlockTypeAt(location, generated);
  734. }
  735. void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
  736. {
  737. int index = Chunk::index(location);
  738. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT && index >= 0);
  739. Block* old = blocks[index];
  740. if (old && old->isTickSource() != TickSourceType::NONE)
  741. { // remove from tick sorces
  742. if (old->isTickSource() == TickSourceType::EACH_TICK)
  743. {
  744. for (Framework::ArrayIterator<Block*> obj
  745. = tickSourcesEachTick.begin();
  746. obj;
  747. obj++)
  748. {
  749. if (obj.val() == old)
  750. {
  751. obj.remove();
  752. break;
  753. }
  754. }
  755. }
  756. else if (old->isTickSource() == TickSourceType::AFTER_WORLD_UPDATE)
  757. {
  758. for (Framework::ArrayIterator<Block*> obj
  759. = tickSourcesAfterUpdate.begin();
  760. obj;
  761. obj++)
  762. {
  763. if (obj.val() == old)
  764. {
  765. obj.remove();
  766. break;
  767. }
  768. }
  769. }
  770. }
  771. bool change = 0;
  772. bool wasLightSource
  773. = old ? old->zBlockType()->isLightSource()
  774. : Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
  775. bool isLightSource = 0;
  776. if (block)
  777. {
  778. change
  779. = blockIds[index] != (unsigned short)block->zBlockType()->getId();
  780. blockIds[index] = (unsigned short)block->zBlockType()->getId();
  781. isLightSource = block->zBlockType()->isLightSource();
  782. }
  783. else
  784. {
  785. if (old != 0)
  786. {
  787. blockIds[index] = BlockTypeEnum::NO_BLOCK;
  788. }
  789. change = old != 0;
  790. }
  791. blocks[index] = block;
  792. if (old) old->release();
  793. if (block && block->isTickSource() != TickSourceType::NONE)
  794. { // add to tick sources
  795. if (block->isTickSource() == TickSourceType::EACH_TICK)
  796. {
  797. tickSourcesEachTick.add(block);
  798. }
  799. else if (block->isTickSource() == TickSourceType::AFTER_WORLD_UPDATE)
  800. {
  801. tickSourcesAfterUpdate.add(block);
  802. }
  803. }
  804. worldUpdated = 1;
  805. if (change)
  806. {
  807. if (isLightSource != wasLightSource)
  808. {
  809. if (isLightSource)
  810. addLightSource(index);
  811. else
  812. removeLightSource(index);
  813. }
  814. if (added)
  815. {
  816. sendBlockInfo(location);
  817. if (block)
  818. {
  819. Game::INSTANCE->updateLightningWithoutWait(getDimensionId(),
  820. Framework::Vec3<int>(
  821. location.x + this->location.x - CHUNK_SIZE / 2,
  822. location.y + this->location.y - CHUNK_SIZE / 2,
  823. location.z));
  824. }
  825. }
  826. }
  827. if (added)
  828. {
  829. Game::INSTANCE->zDimension(dimensionId)
  830. ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
  831. location.y + this->location.y - CHUNK_SIZE / 2,
  832. location.z);
  833. }
  834. }
  835. void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
  836. {
  837. int index = Chunk::index(location);
  838. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
  839. bool wasLightSource
  840. = Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
  841. bool isLightSource = Game::INSTANCE->zBlockType(type)->isLightSource();
  842. if (blockIds[index] != (unsigned short)type)
  843. {
  844. blockIds[index] = (unsigned short)type;
  845. if (isLightSource != wasLightSource)
  846. {
  847. if (isLightSource)
  848. addLightSource(index);
  849. else
  850. removeLightSource(index);
  851. }
  852. if (added)
  853. {
  854. sendBlockInfo(location);
  855. Game::INSTANCE->updateLightningWithoutWait(getDimensionId(),
  856. Framework::Vec3<int>(
  857. location.x + this->location.x - CHUNK_SIZE / 2,
  858. location.y + this->location.y - CHUNK_SIZE / 2,
  859. location.z));
  860. Game::INSTANCE->zDimension(dimensionId)
  861. ->updateMap(location.x + this->location.x - CHUNK_SIZE / 2,
  862. location.y + this->location.y - CHUNK_SIZE / 2,
  863. location.z);
  864. }
  865. worldUpdated = 1;
  866. }
  867. }
  868. void Chunk::sendBlockInfo(Framework::Vec3<int> location)
  869. {
  870. int index = Chunk::index(location);
  871. char* msg = new char[14];
  872. msg[0] = 0; // set block
  873. *(unsigned short*)(msg + 1) = blockIds[index];
  874. *(int*)(msg + 3) = index;
  875. char state = 0;
  876. const BlockType* type = Game::INSTANCE->zBlockType(blockIds[index]);
  877. if (type->isFluid())
  878. {
  879. state |= 1;
  880. }
  881. if ((blocks[index] && blocks[index]->isPassable())
  882. || (type->zDefault()->isPassable()))
  883. {
  884. state |= 2;
  885. }
  886. msg[7] = state;
  887. if ((state | 1) == state)
  888. {
  889. FluidBlock* fluidBlock = dynamic_cast<FluidBlock*>(blocks[index]);
  890. msg[8] = fluidBlock ? fluidBlock->getFlowOptions() : 0;
  891. msg[9] = fluidBlock ? fluidBlock->getDistanceToSource() : 0;
  892. }
  893. if ((state | 2) == state)
  894. {
  895. *(float*)(msg + 10) = blocks[index]
  896. ? blocks[index]->getSpeedModifier()
  897. : type->zDefault()->getSpeedModifier();
  898. }
  899. NetworkMessage* message = new NetworkMessage();
  900. message->addressChunck(this);
  901. message->setMessage(msg, 14);
  902. notifyObservers(message);
  903. if (blocks[index])
  904. {
  905. NetworkMessage* message = new NetworkMessage();
  906. blocks[index]->sendModelInfo(message);
  907. if (message->isEmpty())
  908. {
  909. message->release();
  910. }
  911. else
  912. {
  913. notifyObservers(message);
  914. }
  915. }
  916. cs.lock();
  917. for (int i = 0; i < 6; i++)
  918. {
  919. Direction d = getDirectionFromIndex(i);
  920. Framework::Vec3<int> loc = location + getDirection(d);
  921. if (loc.x >= 0 && loc.x < CHUNK_SIZE && loc.y >= 0 && loc.y < CHUNK_SIZE
  922. && loc.z >= 0 && loc.z < WORLD_HEIGHT)
  923. {
  924. broadcastLightData(Chunk::index(loc), true);
  925. }
  926. else if (loc.z >= 0 && loc.z < WORLD_HEIGHT && i < 4 && zNeighbours[i])
  927. {
  928. NetworkMessage* msg = new NetworkMessage();
  929. msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
  930. char* message = new char[19];
  931. message[0] = 5;
  932. *(int*)(message + 1) = loc.x + this->location.x - CHUNK_SIZE / 2;
  933. *(int*)(message + 5) = loc.y + this->location.y - CHUNK_SIZE / 2;
  934. *(int*)(message + 9) = loc.z;
  935. loc -= getDirection(d) * CHUNK_SIZE;
  936. memcpy(message + 13, zNeighbours[i]->getLightData(loc), 6);
  937. msg->setMessage(message, 19);
  938. notifyObservers(msg);
  939. }
  940. }
  941. cs.unlock();
  942. }
  943. void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
  944. {
  945. cs.lock();
  946. int dirIndex = getDirectionIndex(dir);
  947. Chunk* old = zNeighbours[dirIndex];
  948. zNeighbours[dirIndex] = zChunk;
  949. for (int i = 0; i < CHUNK_SIZE; i++)
  950. {
  951. for (int z = 0; z < WORLD_HEIGHT; z++)
  952. {
  953. int index = 0;
  954. int j = 0;
  955. if (dir == NORTH)
  956. {
  957. index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  958. j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  959. }
  960. else if (dir == EAST)
  961. {
  962. index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  963. j = i * WORLD_HEIGHT + z;
  964. }
  965. else if (dir == SOUTH)
  966. {
  967. index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  968. j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  969. }
  970. else if (dir == WEST)
  971. {
  972. index = i * WORLD_HEIGHT + z;
  973. j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  974. }
  975. bool needsTransmission = 0;
  976. zNeighbours[dirIndex] = old;
  977. bool visible = isVisible(index);
  978. zNeighbours[dirIndex] = zChunk;
  979. if (!visible && isVisible(index))
  980. {
  981. needsTransmission = 1;
  982. }
  983. if (zChunk)
  984. {
  985. if (!blocks[index])
  986. {
  987. if (zChunk->zBlockConst(j)->isTransparent()
  988. && !blockIds[index])
  989. {
  990. generateBlock(Framework::Vec3<int>(
  991. (index / WORLD_HEIGHT) / CHUNK_SIZE,
  992. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  993. index % WORLD_HEIGHT));
  994. }
  995. }
  996. }
  997. if (needsTransmission && added)
  998. {
  999. sendBlockInfo(
  1000. Framework::Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE,
  1001. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  1002. index % WORLD_HEIGHT));
  1003. }
  1004. }
  1005. }
  1006. cs.unlock();
  1007. }
  1008. void Chunk::load(Framework::StreamReader* zReader)
  1009. {
  1010. for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
  1011. {
  1012. unsigned short blockType;
  1013. zReader->lese((char*)&blockType, 2);
  1014. if (blockType)
  1015. {
  1016. Framework::Vec3<int> pos
  1017. = Framework::Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE,
  1018. (index / WORLD_HEIGHT) % CHUNK_SIZE,
  1019. index % WORLD_HEIGHT);
  1020. bool d;
  1021. zReader->lese((char*)&d, 1);
  1022. if (d)
  1023. {
  1024. putBlockAt(pos,
  1025. Game::INSTANCE->zBlockType(blockType)->loadBlock(
  1026. Framework::Vec3<int>(
  1027. pos.x + location.x - CHUNK_SIZE / 2,
  1028. pos.y + location.y - CHUNK_SIZE / 2,
  1029. pos.z),
  1030. zReader,
  1031. dimensionId));
  1032. }
  1033. else
  1034. {
  1035. putBlockTypeAt(pos, blockType);
  1036. }
  1037. }
  1038. }
  1039. initializeLightning();
  1040. }
  1041. void Chunk::save(Framework::StreamWriter* zWriter)
  1042. {
  1043. for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
  1044. {
  1045. unsigned short blockType
  1046. = blocks[index]
  1047. ? (unsigned short)blocks[index]->zBlockType()->getId()
  1048. : blockIds[index];
  1049. zWriter->schreibe((char*)&blockType, 2);
  1050. if (blockType)
  1051. {
  1052. if (blocks[index])
  1053. {
  1054. bool d = 1;
  1055. zWriter->schreibe((char*)&d, 1);
  1056. Game::INSTANCE->zBlockType(blockType)->saveBlock(
  1057. blocks[index], zWriter);
  1058. }
  1059. else
  1060. {
  1061. bool d = 0;
  1062. zWriter->schreibe((char*)&d, 1);
  1063. }
  1064. }
  1065. }
  1066. }
  1067. void Chunk::removeUnusedBlocks()
  1068. {
  1069. /* for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  1070. {
  1071. if (!blocks[i] && blockIds[i])
  1072. {
  1073. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  1074. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  1075. int z = i % WORLD_HEIGHT;
  1076. bool visible = 0;
  1077. if (CONST_BLOCK(0, blockIds[i])->isTransparent()
  1078. || CONST_BLOCK(0, blockIds[i])->isPassable())
  1079. visible = 1;
  1080. else
  1081. {
  1082. for (int d = 0; d < 6 && !visible; d++)
  1083. {
  1084. auto n = zBlockNeighbor(
  1085. getDirection((Directions)getDirectionFromIndex(d))
  1086. + Framework::Vec3<int>(x, y, z),
  1087. 0);
  1088. if (n.isA()
  1089. && (((Block*)n)->isPassable()
  1090. || ((Block*)n)->isTransparent()))
  1091. visible = 1;
  1092. if (n.isB()
  1093. && (CONST_BLOCK(0, n)->isTransparent()
  1094. || CONST_BLOCK(0, n)->isPassable()))
  1095. visible = 1;
  1096. }
  1097. }
  1098. if (!visible)
  1099. {
  1100. putBlockAt({x, y, z}, 0);
  1101. putBlockTypeAt({x, y, z}, 0);
  1102. }
  1103. }
  1104. }*/
  1105. #ifdef _DEBUG
  1106. int count = 0;
  1107. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  1108. {
  1109. if (Game::INSTANCE->zBlockType(blockIds[i])->doesNeedClientInstance())
  1110. count++;
  1111. }
  1112. Framework::Logging::debug()
  1113. << "chunk " << location.x << ", " << location.y
  1114. << " was generated with " << count << " blocks.";
  1115. #endif
  1116. }
  1117. int Chunk::getDimensionId() const
  1118. {
  1119. return dimensionId;
  1120. }
  1121. void Chunk::onLoaded()
  1122. {
  1123. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  1124. {
  1125. if (blocks[i]) blocks[i]->onLoaded();
  1126. }
  1127. currentlyLoading = 0;
  1128. }
  1129. void Chunk::onUnloaded()
  1130. {
  1131. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  1132. {
  1133. if (blocks[i]) blocks[i]->onUnloaded();
  1134. }
  1135. }
  1136. Framework::Punkt Chunk::getCenter() const
  1137. {
  1138. return location;
  1139. }
  1140. Framework::Vec3<int> Chunk::getMin() const
  1141. {
  1142. return {location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0};
  1143. }
  1144. Framework::Vec3<int> Chunk::getMax() const
  1145. {
  1146. return {
  1147. location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT};
  1148. }
  1149. void Chunk::prepareRemove()
  1150. {
  1151. added = 0;
  1152. cs.lock();
  1153. for (int i = 0; i < 4; i++)
  1154. {
  1155. if (zNeighbours[i])
  1156. {
  1157. zNeighbours[i]->setNeighbor(
  1158. getOppositeDirection(getDirectionFromIndex(i)), 0);
  1159. zNeighbours[i] = 0;
  1160. }
  1161. }
  1162. cs.unlock();
  1163. }
  1164. void Chunk::setAdded()
  1165. {
  1166. added = 1;
  1167. }
  1168. bool Chunk::hasObservers() const
  1169. {
  1170. return observers.getEintragAnzahl() > 0 || currentlyLoading;
  1171. }
  1172. unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
  1173. {
  1174. int index = Chunk::index(location) * 6;
  1175. assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
  1176. return lightData + index;
  1177. }
  1178. void Chunk::setLightData(
  1179. Framework::Vec3<int> location, unsigned char* data, bool foreground)
  1180. {
  1181. int index = Chunk::index(location);
  1182. memcpy(lightData + index * 6, data, 6);
  1183. // check if neighbor is a visible block and send update to clients
  1184. bool needSend = 0;
  1185. for (int i = 0; i < 6; i++)
  1186. {
  1187. Framework::Vec3<int> pos
  1188. = location + getDirection(getDirectionFromIndex(i));
  1189. if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
  1190. {
  1191. if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
  1192. && pos.y < CHUNK_SIZE)
  1193. {
  1194. int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
  1195. int type = blockIds[bi];
  1196. needSend |= Game::INSTANCE->zBlockType(type)
  1197. ->doesNeedClientInstance();
  1198. if (needSend) break;
  1199. }
  1200. else
  1201. {
  1202. int type = Game::INSTANCE->getBlockType(
  1203. pos
  1204. + Framework::Vec3<int>(
  1205. this->location.x - CHUNK_SIZE / 2,
  1206. this->location.y - CHUNK_SIZE / 2,
  1207. 0),
  1208. dimensionId);
  1209. needSend |= Game::INSTANCE->zBlockType(type)
  1210. ->doesNeedClientInstance();
  1211. if (needSend) break;
  1212. }
  1213. }
  1214. }
  1215. if (needSend)
  1216. {
  1217. broadcastLightData(index, foreground);
  1218. }
  1219. }
  1220. int Chunk::getBlockTypeAt(Framework::Vec3<int> location) const
  1221. {
  1222. return blockIds[index(location)];
  1223. }
  1224. int Chunk::getBlockTypeAtWC(int x, int y, int z) const
  1225. {
  1226. return blockIds[index(Dimension::chunkCoordinates({x, y, z}))];
  1227. }
  1228. void Chunk::onEntityEnters(Entity* zEntity, Chunk* lastChunk)
  1229. {
  1230. NetworkMessage* msg = 0;
  1231. for (InformationObserver* observer : observers)
  1232. {
  1233. if (!lastChunk || !lastChunk->hasObserver(zEntity->getId()))
  1234. {
  1235. if (!msg)
  1236. {
  1237. msg = new NetworkMessage();
  1238. msg->addEntityMessage(zEntity);
  1239. if (msg->isEmpty()) break;
  1240. }
  1241. observer->sendMessage(
  1242. dynamic_cast<NetworkMessage*>(msg->getThis()));
  1243. }
  1244. }
  1245. if (msg) msg->release();
  1246. }
  1247. void Chunk::onEntityLeaves(Entity* zEntity, Chunk* zNextChunk)
  1248. {
  1249. NetworkMessage* msg = 0;
  1250. for (InformationObserver* observer : observers)
  1251. {
  1252. if (!zNextChunk || !zNextChunk->hasObserver(zEntity->getId()))
  1253. {
  1254. if (!msg)
  1255. {
  1256. msg = new NetworkMessage();
  1257. msg->removeEntityMessage(zEntity);
  1258. if (msg->isEmpty()) break;
  1259. }
  1260. observer->sendMessage(
  1261. dynamic_cast<NetworkMessage*>(msg->getThis()));
  1262. }
  1263. }
  1264. if (msg) msg->release();
  1265. }
  1266. bool Chunk::hasObserver(int entityId) const
  1267. {
  1268. for (InformationObserver* observer : observers)
  1269. {
  1270. if (observer->getEntityId() == entityId) return 1;
  1271. }
  1272. return 0;
  1273. }