Chunk.cpp 45 KB

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