Chunk.cpp 21 KB

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