Chunk.cpp 22 KB

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