Chunk.cpp 45 KB

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