Chunk.cpp 22 KB

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