Chunk.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. #include <InMemoryBuffer.h>
  2. #include "Chunk.h"
  3. #include "Constants.h"
  4. #include "Game.h"
  5. #include "NoBlock.h"
  6. Chunk::Chunk(Framework::Punkt location, int dimensionId)
  7. : ReferenceCounter(),
  8. dimensionId(dimensionId),
  9. location(location),
  10. added(0)
  11. {
  12. blocks = new Block * [CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  13. blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
  14. memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
  15. memset(blockIds, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
  16. zNeighbours[0] = 0;
  17. zNeighbours[1] = 0;
  18. zNeighbours[2] = 0;
  19. zNeighbours[3] = 0;
  20. }
  21. Chunk::Chunk(Framework::Punkt location, int dimensionId, Framework::StreamReader* zReader)
  22. : Chunk(location, dimensionId)
  23. {
  24. load(zReader);
  25. }
  26. Chunk::~Chunk()
  27. {
  28. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  29. {
  30. if (blocks[i])
  31. blocks[i]->release();
  32. }
  33. delete[] blocks;
  34. delete[] blockIds;
  35. }
  36. Framework::Either<Block*, int> Chunk::zBlockNeighbor(Framework::Vec3<int> location)
  37. {
  38. if (location.x >= 0 && location.x < CHUNK_SIZE && location.y >= 0 && location.y < CHUNK_SIZE && location.z >= 0 && location.z < WORLD_HEIGHT)
  39. {
  40. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  41. if (blocks[index])
  42. return blocks[index];
  43. else
  44. return (int)blockIds[index];
  45. }
  46. if (added && location.z >= 0 && location.z < WORLD_HEIGHT)
  47. return Game::INSTANCE->zBlockAt({ location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z }, dimensionId);
  48. return 0;
  49. }
  50. void Chunk::notifyObservers(NetworkMessage& msg)
  51. {
  52. Array<int> remove;
  53. int index = 0;
  54. for (int id : observers)
  55. {
  56. Entity* zE = Game::INSTANCE->zEntity(id);
  57. if (!zE)
  58. remove.add(index, 0);
  59. else
  60. Game::INSTANCE->sendMessage(&msg, zE);
  61. index++;
  62. }
  63. for (int i : remove)
  64. observers.remove(i);
  65. }
  66. void Chunk::addObserver(Entity* zEntity)
  67. {
  68. for (int id : observers)
  69. {
  70. if (id == zEntity->getId())
  71. return;
  72. }
  73. observers.add(zEntity->getId());
  74. InMemoryBuffer buffer;
  75. buffer.schreibe("\4", 1);
  76. buffer.schreibe((char*)&location.x, 4);
  77. buffer.schreibe((char*)&location.y, 4);
  78. sendToClient(&buffer);
  79. NetworkMessage msg;
  80. msg.addressDimension();
  81. char* message = new char[buffer.getSize()];
  82. buffer.lese(message, (int)buffer.getSize());
  83. msg.setMessage(message, (int)buffer.getSize(), 1);
  84. msg.setUseBackground();
  85. Game::INSTANCE->sendMessage(&msg, zEntity);
  86. }
  87. void Chunk::removeObserver(Entity* zEntity)
  88. {
  89. int index = 0;
  90. for (int id : observers)
  91. {
  92. if (id == zEntity->getId())
  93. {
  94. observers.remove(index);
  95. return;
  96. }
  97. index++;
  98. }
  99. }
  100. void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource)
  101. {
  102. // TODO: answer api messages
  103. char type;
  104. zRequest->lese(&type, 1);
  105. switch (type)
  106. {
  107. case 0:
  108. // register observer
  109. addObserver(zSource);
  110. break;
  111. case 1:
  112. // unsubscribe
  113. removeObserver(zSource);
  114. break;
  115. }
  116. }
  117. Framework::Either<Block*, int> Chunk::zBlockAt(Framework::Vec3<int> location) const
  118. {
  119. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  120. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  121. if (blocks[index])
  122. return blocks[index];
  123. else
  124. return (int)blockIds[index];
  125. }
  126. const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
  127. {
  128. auto b = zBlockAt(location);
  129. if (b.isA())
  130. return b;
  131. if (b.getB())
  132. return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->zDefault();
  133. return 0;
  134. }
  135. void Chunk::instantiateBlock(Framework::Vec3<int> location)
  136. {
  137. auto b = zBlockAt(location);
  138. if (b.isA())
  139. return;
  140. if (!b.getB())
  141. generateBlock(location);
  142. b = zBlockAt(location);
  143. if (b.isB())
  144. 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));
  145. }
  146. void Chunk::generateBlock(Framework::Vec3<int> location)
  147. {
  148. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  149. if (blockIds[index])
  150. return;
  151. 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);
  152. if (generated.isA())
  153. putBlockAt(location, generated);
  154. else
  155. putBlockTypeAt(location, generated);
  156. }
  157. void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
  158. {
  159. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  160. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT&& index >= 0);
  161. Block* old = blocks[index];
  162. if (block)
  163. blockIds[index] = (unsigned short)block->zBlockType()->getId();
  164. blocks[index] = block;
  165. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  166. if (neighbor.isA())
  167. ((Block*)neighbor)->setNeighbour(SOUTH, block);
  168. if (block)
  169. block->setNeighbour(NORTH, neighbor);
  170. neighbor = zBlockNeighbor(location + getDirection(EAST));
  171. if (neighbor.isA())
  172. ((Block*)neighbor)->setNeighbour(WEST, block);
  173. if (block)
  174. block->setNeighbour(EAST, neighbor);
  175. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  176. if (neighbor.isA())
  177. ((Block*)neighbor)->setNeighbour(NORTH, block);
  178. if (block)
  179. block->setNeighbour(SOUTH, neighbor);
  180. neighbor = zBlockNeighbor(location + getDirection(WEST));
  181. if (neighbor.isA())
  182. ((Block*)neighbor)->setNeighbour(EAST, block);
  183. if (block)
  184. block->setNeighbour(WEST, neighbor);
  185. neighbor = zBlockNeighbor(location + getDirection(TOP));
  186. if (neighbor.isA())
  187. ((Block*)neighbor)->setNeighbour(BOTTOM, block);
  188. if (block)
  189. block->setNeighbour(TOP, neighbor);
  190. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  191. if (neighbor.isA())
  192. ((Block*)neighbor)->setNeighbour(TOP, block);
  193. if (block)
  194. block->setNeighbour(BOTTOM, neighbor);
  195. if (old)
  196. old->release();
  197. char msg[9];
  198. msg[0] = 0; // set block
  199. *(int*)(msg + 1) = index;
  200. *(int*)(msg + 5) = block ? block->zBlockType()->getId() : NoBlockBlockType::ID;
  201. NetworkMessage message;
  202. message.addressChunck(this);
  203. message.setMessage(msg, 9, 0);
  204. notifyObservers(message);
  205. }
  206. void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
  207. {
  208. int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
  209. assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
  210. blockIds[index] = (unsigned short)type;
  211. Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
  212. if (neighbor.isA())
  213. ((Block*)neighbor)->setNeighbourType(SOUTH, type);
  214. neighbor = zBlockNeighbor(location + getDirection(EAST));
  215. if (neighbor.isA())
  216. ((Block*)neighbor)->setNeighbourType(WEST, type);
  217. neighbor = zBlockNeighbor(location + getDirection(SOUTH));
  218. if (neighbor.isA())
  219. ((Block*)neighbor)->setNeighbourType(NORTH, type);
  220. neighbor = zBlockNeighbor(location + getDirection(WEST));
  221. if (neighbor.isA())
  222. ((Block*)neighbor)->setNeighbourType(EAST, type);
  223. neighbor = zBlockNeighbor(location + getDirection(TOP));
  224. if (neighbor.isA())
  225. ((Block*)neighbor)->setNeighbourType(BOTTOM, type);
  226. neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
  227. if (neighbor.isA())
  228. ((Block*)neighbor)->setNeighbourType(TOP, type);
  229. char msg[9];
  230. msg[0] = 0; // set block
  231. *(int*)(msg + 1) = index;
  232. *(int*)(msg + 5) = type;
  233. NetworkMessage message;
  234. message.addressChunck(this);
  235. message.setMessage(msg, 9, 0);
  236. notifyObservers(message);
  237. }
  238. void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
  239. {
  240. zNeighbours[getDirectionIndex(dir)] = zChunk;
  241. for (int i = 0; i < CHUNK_SIZE; i++)
  242. {
  243. for (int z = 0; z < WORLD_HEIGHT; z++)
  244. {
  245. if (dir == NORTH)
  246. {
  247. int index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  248. if (blocks[index])
  249. {
  250. int j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  251. if (zChunk && zChunk->blocks[j])
  252. blocks[index]->setNeighbour(NORTH, zChunk->blocks[j]);
  253. else
  254. {
  255. blocks[index]->setNeighbour(NORTH, 0);
  256. blocks[index]->setNeighbourType(NORTH, zChunk ? zChunk->blockIds[j] : 0);
  257. }
  258. }
  259. }
  260. else if (dir == EAST)
  261. {
  262. int index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  263. if (blocks[index])
  264. {
  265. int j = i * WORLD_HEIGHT + z;
  266. if (zChunk && zChunk->blocks[j])
  267. blocks[index]->setNeighbour(EAST, zChunk->blocks[j]);
  268. else
  269. {
  270. blocks[index]->setNeighbour(EAST, 0);
  271. blocks[index]->setNeighbourType(EAST, zChunk ? zChunk->blockIds[j] : 0);
  272. }
  273. }
  274. }
  275. else if (dir == SOUTH)
  276. {
  277. int index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
  278. if (blocks[index])
  279. {
  280. int j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
  281. if (zChunk && zChunk->blocks[j])
  282. blocks[index]->setNeighbour(SOUTH, zChunk->blocks[j]);
  283. else
  284. {
  285. blocks[index]->setNeighbour(SOUTH, 0);
  286. blocks[index]->setNeighbourType(SOUTH, zChunk ? zChunk->blockIds[j] : 0);
  287. }
  288. }
  289. }
  290. else if (dir == WEST)
  291. {
  292. int index = i * WORLD_HEIGHT + z;
  293. if (blocks[index])
  294. {
  295. int j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
  296. if (zChunk && zChunk->blocks[j])
  297. blocks[index]->setNeighbour(WEST, zChunk->blocks[j]);
  298. else
  299. {
  300. blocks[index]->setNeighbour(WEST, 0);
  301. blocks[index]->setNeighbourType(WEST, zChunk ? zChunk->blockIds[j] : 0);
  302. }
  303. }
  304. }
  305. }
  306. }
  307. }
  308. void Chunk::load(Framework::StreamReader* zReader)
  309. {
  310. unsigned short id = 0;
  311. zReader->lese((char*)&id, 2);
  312. Framework::Vec3<int> pos;
  313. bool d = 0;
  314. while (id)
  315. {
  316. zReader->lese((char*)&pos.x, 4);
  317. zReader->lese((char*)&pos.y, 4);
  318. zReader->lese((char*)&pos.z, 4);
  319. zReader->lese((char*)&d, 1);
  320. if (d)
  321. 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));
  322. else
  323. putBlockTypeAt(pos, id);
  324. zReader->lese((char*)&id, 2);
  325. }
  326. }
  327. void Chunk::save(Framework::StreamWriter* zWriter)
  328. {
  329. for (int x = 0; x < CHUNK_SIZE; x++)
  330. {
  331. for (int y = 0; y < CHUNK_SIZE; y++)
  332. {
  333. for (int z = 0; z < WORLD_HEIGHT; z++)
  334. {
  335. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  336. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  337. if (blockType)
  338. {
  339. zWriter->schreibe((char*)&blockType, 2);
  340. zWriter->schreibe((char*)&x, 4);
  341. zWriter->schreibe((char*)&y, 4);
  342. zWriter->schreibe((char*)&z, 4);
  343. if (blocks[index])
  344. {
  345. bool d = 1;
  346. zWriter->schreibe((char*)&d, 1);
  347. StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->saveBlock(blocks[index], zWriter);
  348. }
  349. else
  350. {
  351. bool d = 0;
  352. zWriter->schreibe((char*)&d, 1);
  353. }
  354. }
  355. }
  356. }
  357. }
  358. unsigned short end = 0;
  359. zWriter->schreibe((char*)&end, 2);
  360. }
  361. void Chunk::sendToClient(Framework::StreamWriter* zWriter)
  362. {
  363. for (int x = 0; x < CHUNK_SIZE; x++)
  364. {
  365. for (int y = 0; y < CHUNK_SIZE; y++)
  366. {
  367. for (int z = 0; z < WORLD_HEIGHT; z++)
  368. {
  369. int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
  370. unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
  371. if (blockType)
  372. {
  373. bool visible = 0;
  374. if (!visible)
  375. {
  376. if (!blocks[index])
  377. {
  378. if (CONST_BLOCK(0, blockIds[index])->isTransparent() || CONST_BLOCK(0, blockIds[index])->isPassable())
  379. visible = 1;
  380. else
  381. {
  382. for (int d = 0; d < 6 && !visible; d++)
  383. {
  384. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  385. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  386. visible = 1;
  387. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  388. visible = 1;
  389. }
  390. }
  391. }
  392. else
  393. visible = blocks[index]->isVisible();
  394. }
  395. if (visible && (blocks[index] || blockType != AirBlockBlockType::ID))
  396. {
  397. zWriter->schreibe((char*)&blockType, 2);
  398. zWriter->schreibe((char*)&x, 4);
  399. zWriter->schreibe((char*)&y, 4);
  400. zWriter->schreibe((char*)&z, 4);
  401. }
  402. }
  403. }
  404. }
  405. }
  406. unsigned short end = 0;
  407. zWriter->schreibe((char*)&end, 2);
  408. }
  409. void Chunk::removeUnusedBlocks()
  410. {
  411. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  412. {
  413. if (blocks[i])
  414. {
  415. if (!blocks[i]->isVisible())
  416. {
  417. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  418. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  419. int z = i % WORLD_HEIGHT;
  420. putBlockAt({ x,y,z }, 0);
  421. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  422. }
  423. }
  424. else if (blockIds[i])
  425. {
  426. int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
  427. int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
  428. int z = i % WORLD_HEIGHT;
  429. bool visible = 0;
  430. if (CONST_BLOCK(0, blockIds[i])->isTransparent() || CONST_BLOCK(0, blockIds[i])->isPassable())
  431. visible = 1;
  432. else
  433. {
  434. for (int d = 0; d < 6 && !visible; d++)
  435. {
  436. auto n = zBlockNeighbor(getDirection((Directions)getDirectionFromIndex(d)) + Framework::Vec3<int>(x, y, z));
  437. if (n.isA() && (((Block*)n)->isPassable() || ((Block*)n)->isTransparent()))
  438. visible = 1;
  439. if (n.isB() && (CONST_BLOCK(0, n)->isTransparent() || CONST_BLOCK(0, n)->isPassable()))
  440. visible = 1;
  441. }
  442. }
  443. if (!visible)
  444. {
  445. putBlockAt({ x,y,z }, 0);
  446. putBlockTypeAt({ x, y, z }, NoBlockBlockType::ID);
  447. }
  448. }
  449. }
  450. int count = 0;
  451. for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
  452. {
  453. if (blockIds[i] && blockIds[i] != AirBlockBlockType::ID)
  454. count++;
  455. }
  456. std::cout << "chunk " << location.x << ", " << location.y << " was generated with " << count << " blocks.\n";
  457. }
  458. int Chunk::getDimensionId() const
  459. {
  460. return dimensionId;
  461. }
  462. Framework::Punkt Chunk::getCenter() const
  463. {
  464. return location;
  465. }
  466. Framework::Vec3<int> Chunk::getMin() const
  467. {
  468. return { location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0 };
  469. }
  470. Framework::Vec3<int> Chunk::getMax() const
  471. {
  472. return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT };
  473. }
  474. void Chunk::prepareRemove()
  475. {
  476. added = 0;
  477. for (int i = 0; i < 4; i++)
  478. {
  479. if (zNeighbours[i])
  480. {
  481. zNeighbours[i]->setNeighbor(getOppositeDirection(getDirectionFromIndex(i)), 0);
  482. zNeighbours[i] = 0;
  483. }
  484. }
  485. }
  486. void Chunk::setAdded()
  487. {
  488. added = 1;
  489. }
  490. bool Chunk::hasObservers() const
  491. {
  492. return observers.getEintragAnzahl() > 0;
  493. }