Dimension.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. #include "Dimension.h"
  2. #include "Constants.h"
  3. #include "Datei.h"
  4. #include "Game.h"
  5. #include "NoBlock.h"
  6. using namespace Framework;
  7. Dimension::Dimension(int id)
  8. : Thread(),
  9. nextStructureId(0),
  10. dimensionId(id),
  11. gravity(9.8f),
  12. chunks(new RCTrie<Chunk>()),
  13. entities(new RCArray<Entity>()),
  14. map(new DimensionMap(id)),
  15. stop(0)
  16. {
  17. Datei d;
  18. d.setDatei(
  19. Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(id) + "/nst.id");
  20. if (d.existiert())
  21. {
  22. d.open(Datei::Style::lesen);
  23. d.lese((char*)&nextStructureId, 8);
  24. d.close();
  25. }
  26. start();
  27. }
  28. Dimension::~Dimension()
  29. {
  30. entities->release();
  31. chunks->release();
  32. map->release();
  33. }
  34. void Dimension::api(Framework::InMemoryBuffer* zRequest,
  35. NetworkMessage* zResponse,
  36. Entity* zSource)
  37. {
  38. DoLaterHandler laterHandler;
  39. char type;
  40. zRequest->lese(&type, 1);
  41. switch (type)
  42. {
  43. case 0: // chunk message
  44. {
  45. Punkt center;
  46. zRequest->lese((char*)&center.x, 4);
  47. zRequest->lese((char*)&center.y, 4);
  48. cs.lock();
  49. Chunk* cC = zChunk(Game::getChunkCenter(center.x, center.y));
  50. if (!cC)
  51. {
  52. // TODO: have a max amount of waiting requests per player
  53. waitingRequests.add(
  54. {dynamic_cast<InMemoryBuffer*>(zRequest->getThis()),
  55. center,
  56. zSource->getId()});
  57. Game::INSTANCE->requestArea({center.x - CHUNK_SIZE / 2,
  58. center.y - CHUNK_SIZE / 2,
  59. center.x + CHUNK_SIZE / 2 - 1,
  60. center.y + CHUNK_SIZE / 2 - 1,
  61. dimensionId});
  62. }
  63. else
  64. {
  65. cC->api(zRequest, zSource, laterHandler);
  66. }
  67. cs.unlock();
  68. break;
  69. }
  70. case 1: // block message
  71. {
  72. Vec3<int> location;
  73. zRequest->lese((char*)&location.x, 4);
  74. zRequest->lese((char*)&location.y, 4);
  75. zRequest->lese((char*)&location.z, 4);
  76. Framework::Either<Block*, int> block = zBlock(location);
  77. if (block.isA())
  78. {
  79. block.getA()->api(zRequest, zResponse);
  80. }
  81. break;
  82. }
  83. case 2: // map request
  84. {
  85. map->api(zRequest, zResponse, zSource, this);
  86. break;
  87. }
  88. }
  89. }
  90. void Dimension::tickEntities()
  91. {
  92. for (auto entity : *entities)
  93. {
  94. if (!entity->isRemoved()
  95. && (entity->isMoving()
  96. || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
  97. (int)entity->getPosition().y))))
  98. entity->prepareTick(this);
  99. }
  100. int index = 0;
  101. for (auto entity : *entities)
  102. {
  103. if (!entity->isRemoved()
  104. && (entity->isMoving()
  105. || zChunk(Game::getChunkCenter((int)entity->getPosition().x,
  106. (int)entity->getPosition().y))))
  107. entity->tick(this);
  108. index++;
  109. }
  110. }
  111. void Dimension::thread()
  112. {
  113. // light calculation
  114. int index = 0;
  115. ZeitMesser messer;
  116. messer.messungStart();
  117. double time = 0;
  118. bool isForeground = 0;
  119. Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
  120. while (!stop)
  121. {
  122. Vec3<int> position;
  123. if (internalLightUpdateQueue.getEintragAnzahl())
  124. {
  125. position = internalLightUpdateQueue.get(0);
  126. internalLightUpdateQueue.remove(0);
  127. }
  128. else
  129. {
  130. removedChunksCs.lock();
  131. if (removedChunks.getEintragAnzahl() > 0)
  132. {
  133. Chunk* removedChunk = removedChunks.z(0);
  134. removedChunksCs.unlock();
  135. Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/"
  136. + getDimensionId() + "/";
  137. filePath.appendHex(removedChunk->getCenter().x);
  138. filePath += "_";
  139. filePath.appendHex(removedChunk->getCenter().y);
  140. filePath += ".chunk";
  141. Datei d;
  142. d.setDatei(filePath);
  143. d.erstellen();
  144. d.open(Datei::Style::schreiben);
  145. removedChunk->save(&d);
  146. char addr[8];
  147. getAddrOfWorld(removedChunk->getCenter(), addr);
  148. map->removeMap(addr, 8);
  149. d.close();
  150. removedChunksCs.lock();
  151. removedChunks.remove(0);
  152. }
  153. removedChunksCs.unlock();
  154. if (priorizedLightUpdateQueue.getEintragAnzahl())
  155. {
  156. prioLightCs.lock();
  157. position = priorizedLightUpdateQueue.get(0);
  158. priorizedLightUpdateQueue.remove(0);
  159. prioLightCs.unlock();
  160. isForeground = 1;
  161. }
  162. else
  163. {
  164. if (!lightUpdateQueue.getEintragAnzahl())
  165. {
  166. messer.messungEnde();
  167. time += messer.getSekunden();
  168. Sleep(500);
  169. messer.messungStart();
  170. continue;
  171. }
  172. lightCs.lock();
  173. position = lightUpdateQueue.get(0);
  174. lightUpdateQueue.remove(0);
  175. lightCs.unlock();
  176. isForeground = 0;
  177. }
  178. }
  179. Chunk* chunk
  180. = zChunk(Game::INSTANCE->getChunkCenter(position.x, position.y));
  181. if (position.z >= 0 && position.z < WORLD_HEIGHT)
  182. {
  183. if (chunk)
  184. {
  185. Vec3<int> chunkPos = chunkCoordinates(position);
  186. unsigned char* light = chunk->getLightData(chunkPos);
  187. unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
  188. unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
  189. unsigned char newLight[6] = {0, 0, 0, 0, 0, 0};
  190. // add neighbor light emission
  191. for (int i = 0; i < 6; i++)
  192. {
  193. unsigned char* neighborLeight;
  194. Vec3<int> neighborPos
  195. = position + getDirection(getDirectionFromIndex(i));
  196. if (neighborPos.z < 0)
  197. {
  198. neighborLeight = noLight;
  199. }
  200. else if (neighborPos.z >= WORLD_HEIGHT)
  201. {
  202. neighborLeight = dayLight;
  203. }
  204. else
  205. {
  206. Chunk* neighborChunk
  207. = zChunk(Game::INSTANCE->getChunkCenter(
  208. neighborPos.x, neighborPos.y));
  209. if (neighborChunk)
  210. neighborLeight = neighborChunk->getLightData(
  211. chunkCoordinates(neighborPos));
  212. else
  213. neighborLeight = noLight;
  214. }
  215. for (int j = 0; j < 3; j++)
  216. newLight[j] = (unsigned char)MAX(newLight[j],
  217. i == getDirectionIndex(TOP)
  218. ? neighborLeight[j]
  219. : (unsigned char)((float)neighborLeight[j]
  220. * 0.8f));
  221. for (int j = 3; j < 6; j++)
  222. newLight[j] = (unsigned char)MAX(newLight[j],
  223. (unsigned char)((float)neighborLeight[j] * 0.85f));
  224. }
  225. const Block* current = zBlockOrDefault(position);
  226. // add own light emission
  227. for (int j = 3; j < 6; j++)
  228. newLight[j] = (unsigned char)MAX(
  229. newLight[j], current->getLightEmisionColor()[j - 3]);
  230. current->filterPassingLight(newLight);
  231. current->filterPassingLight(newLight + 3);
  232. for (int i = 0; i < 6; i++)
  233. {
  234. if (newLight[i] != light[i])
  235. {
  236. chunk->setLightData(chunkPos,
  237. newLight,
  238. isForeground);
  239. for (int j = 0; j < 6; j++)
  240. internalLightUpdateQueue.add(
  241. position
  242. + getDirection(getDirectionFromIndex(j)),
  243. 0);
  244. break;
  245. }
  246. }
  247. }
  248. }
  249. index++;
  250. if (index > 100000)
  251. {
  252. messer.messungEnde();
  253. time += messer.getSekunden();
  254. std::cout << "100000 light updates needed " << time << " seconds\n";
  255. time = 0;
  256. index = 0;
  257. messer.messungStart();
  258. }
  259. }
  260. std::cout << Text("Dimension ") + this->getDimensionId()
  261. + " update Thread exited.\n";
  262. }
  263. void Dimension::getAddrOf(Punkt cPos, char* addr) const
  264. {
  265. *(int*)addr = cPos.x;
  266. *((int*)addr + 1) = cPos.y;
  267. }
  268. void Dimension::getAddrOfWorld(Punkt wPos, char* addr) const
  269. {
  270. if (wPos.x < 0) wPos.x -= CHUNK_SIZE;
  271. if (wPos.y < 0) // needed because otherwise would (-8, -8) have the same
  272. // adress as (8, 8)
  273. wPos.y -= CHUNK_SIZE;
  274. wPos /= CHUNK_SIZE;
  275. getAddrOf(wPos, addr);
  276. }
  277. void Dimension::saveStructure(MultiblockStructure* zStructure) const
  278. {
  279. Datei d;
  280. Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
  281. + Text(dimensionId) + "/structures/";
  282. path.appendHex(zStructure->getStructureId());
  283. path += ".str";
  284. d.setDatei(path);
  285. d.erstellen();
  286. d.open(Datei::Style::schreiben);
  287. auto uPos = zStructure->getUniquePosition();
  288. d.schreibe((char*)&uPos.x, 4);
  289. d.schreibe((char*)&uPos.y, 4);
  290. d.schreibe((char*)&uPos.z, 4);
  291. int typeId = zStructure->getStructureTypeId();
  292. d.schreibe((char*)&typeId, 4);
  293. __int64 strId = zStructure->getStructureId();
  294. d.schreibe((char*)&strId, 8);
  295. StaticRegistry<MultiblockStructureType>::INSTANCE
  296. .zElement(zStructure->getStructureTypeId())
  297. ->saveStructure(zStructure, &d);
  298. d.close();
  299. }
  300. Chunk* Dimension::zChunk(Punkt wPos) const
  301. {
  302. char addr[8];
  303. getAddrOfWorld(wPos, addr);
  304. return chunks->z(addr, 8);
  305. }
  306. Framework::Either<Block*, int> Dimension::zBlock(Vec3<int> location)
  307. {
  308. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  309. if (c)
  310. {
  311. location = chunkCoordinates(location);
  312. return c->zBlockAt(location);
  313. }
  314. return 0;
  315. }
  316. Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
  317. {
  318. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  319. if (c)
  320. {
  321. location = chunkCoordinates(location);
  322. c->instantiateBlock(location);
  323. auto result = c->zBlockAt(location);
  324. return result.isA() ? result.getA() : 0;
  325. }
  326. return 0;
  327. }
  328. const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
  329. {
  330. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  331. if (c)
  332. {
  333. location = chunkCoordinates(location);
  334. return c->zBlockConst(location);
  335. }
  336. return &NoBlock::INSTANCE;
  337. }
  338. int Dimension::getBlockType(Framework::Vec3<int> location) {
  339. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  340. if (c)
  341. {
  342. location = chunkCoordinates(location);
  343. return c->getBlockTypeAt(location);
  344. }
  345. return BlockTypeEnum::NO_BLOCK;
  346. }
  347. void Dimension::placeBlock(
  348. Framework::Vec3<int> location, Framework::Either<Block*, int> block)
  349. {
  350. Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
  351. if (c)
  352. {
  353. location = chunkCoordinates(location);
  354. if (block.isA())
  355. c->putBlockAt(location, block);
  356. else
  357. {
  358. c->putBlockAt(location, 0);
  359. c->putBlockTypeAt(location, block);
  360. }
  361. }
  362. else if (block.isA())
  363. block.getA()->release();
  364. }
  365. void Dimension::sendBlockInfo(Framework::Vec3<int> location)
  366. {
  367. Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
  368. if (c)
  369. {
  370. location = chunkCoordinates(location);
  371. c->sendBlockInfo(location);
  372. }
  373. }
  374. void Dimension::addEntity(Entity* entity)
  375. {
  376. entities->add(entity);
  377. }
  378. void Dimension::setChunk(Chunk* chunk, Punkt center)
  379. {
  380. char addr[8];
  381. getAddrOfWorld(center, addr);
  382. if (chunk) map->loadMap(addr, 8, chunk);
  383. chunkCs.lock();
  384. Chunk* old = chunks->get(addr, 8);
  385. if (old)
  386. {
  387. Game::INSTANCE->zTickOrganizer()->removeTickSource(old);
  388. old->prepareRemove();
  389. for (int i = 0; i < chunkList.getEintragAnzahl(); i++)
  390. {
  391. if (chunkList.get(i) == old)
  392. {
  393. chunkList.remove(i);
  394. break;
  395. }
  396. }
  397. }
  398. chunks->set(addr, 8, chunk);
  399. if (chunk)
  400. {
  401. chunkList.add(chunk);
  402. chunk->setAdded();
  403. }
  404. getAddrOfWorld(center + Punkt(CHUNK_SIZE, 0), addr);
  405. Chunk* zChunk = chunks->z(addr, 8);
  406. if (zChunk)
  407. {
  408. zChunk->setNeighbor(WEST, chunk);
  409. if (chunk)
  410. {
  411. chunk->setNeighbor(EAST, zChunk);
  412. }
  413. }
  414. getAddrOfWorld(center + Punkt(-CHUNK_SIZE, 0), addr);
  415. zChunk = chunks->z(addr, 8);
  416. if (zChunk)
  417. {
  418. zChunk->setNeighbor(EAST, chunk);
  419. if (chunk) chunk->setNeighbor(WEST, zChunk);
  420. }
  421. getAddrOfWorld(center + Punkt(0, CHUNK_SIZE), addr);
  422. zChunk = chunks->z(addr, 8);
  423. if (zChunk)
  424. {
  425. zChunk->setNeighbor(NORTH, chunk);
  426. if (chunk) chunk->setNeighbor(SOUTH, zChunk);
  427. }
  428. getAddrOfWorld(center + Punkt(0, -CHUNK_SIZE), addr);
  429. zChunk = chunks->z(addr, 8);
  430. if (zChunk)
  431. {
  432. zChunk->setNeighbor(SOUTH, chunk);
  433. if (chunk) chunk->setNeighbor(NORTH, zChunk);
  434. }
  435. DoLaterHandler laterHandler;
  436. if (chunk)
  437. {
  438. cs.lock();
  439. int index = 0;
  440. for (Iterator<RequestQueue> iterator = waitingRequests.begin();
  441. iterator;)
  442. {
  443. Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
  444. if (zE)
  445. {
  446. if (iterator.val().chunkCenter == chunk->getCenter())
  447. {
  448. chunk->api(iterator.val().request, zE, laterHandler);
  449. iterator.val().request->release();
  450. iterator.remove();
  451. continue;
  452. }
  453. }
  454. else
  455. {
  456. iterator.val().request->release();
  457. iterator.remove();
  458. continue;
  459. }
  460. iterator++;
  461. index++;
  462. }
  463. cs.unlock();
  464. Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
  465. }
  466. chunkCs.unlock();
  467. if (old)
  468. {
  469. old->onUnloaded();
  470. removedChunksCs.lock();
  471. removedChunks.add(old);
  472. removedChunksCs.unlock();
  473. }
  474. if (chunk) chunk->onLoaded();
  475. laterHandler.execute();
  476. updateLightAtChunkBorders(center);
  477. }
  478. void Dimension::save(Text worldDir) const
  479. {
  480. Datei d;
  481. d.setDatei(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
  482. + "/nst.id");
  483. d.erstellen();
  484. d.open(Datei::Style::schreiben);
  485. d.schreibe((char*)&nextStructureId, 8);
  486. d.close();
  487. for (auto chunk = chunkList.begin(); chunk; chunk++)
  488. {
  489. if (!chunk._) continue;
  490. Datei* file = new Datei();
  491. Text filePath = worldDir + "/dim/" + dimensionId + "/";
  492. filePath.appendHex(chunk->getCenter().x);
  493. filePath += "_";
  494. filePath.appendHex(chunk->getCenter().y);
  495. filePath += ".chunk";
  496. file->setDatei(filePath);
  497. if (file->open(Datei::Style::schreiben)) chunk->save(file);
  498. file->close();
  499. file->release();
  500. char addr[8];
  501. getAddrOfWorld(chunk->getCenter(), addr);
  502. map->saveMap(addr, 8);
  503. }
  504. Text filePath = worldDir + "/dim/" + dimensionId + "/entities";
  505. Datei* file = new Datei();
  506. file->setDatei(filePath);
  507. if (file->open(Datei::Style::schreiben))
  508. {
  509. for (Entity* entity : *entities)
  510. {
  511. if (entity->zType()->getId() != EntityTypeEnum::PLAYER)
  512. {
  513. if (!entity->isRemoved())
  514. {
  515. int type = entity->zType()->getId();
  516. file->schreibe((char*)&type, 4);
  517. StaticRegistry<EntityType>::INSTANCE.zElement(type)
  518. ->saveEntity(entity, file);
  519. }
  520. }
  521. else
  522. {
  523. Datei pFile;
  524. pFile.setDatei(worldDir + "/player/"
  525. + Game::INSTANCE->getPlayerId(
  526. ((Player*)entity)->getName()));
  527. if (pFile.open(Datei::Style::schreiben))
  528. StaticRegistry<EntityType>::INSTANCE
  529. .zElement(EntityTypeEnum::PLAYER)
  530. ->saveEntity(entity, &pFile);
  531. }
  532. }
  533. file->close();
  534. }
  535. for (MultiblockStructure* structure : structures)
  536. {
  537. saveStructure(structure);
  538. }
  539. }
  540. int Dimension::getDimensionId() const
  541. {
  542. return dimensionId;
  543. }
  544. bool Dimension::hasChunck(int x, int y)
  545. {
  546. if (zChunk(Punkt(x, y))) return 1;
  547. removedChunksCs.lock();
  548. for (Chunk* c : removedChunks)
  549. {
  550. if (c->getCenter().x == x && c->getCenter().y == y)
  551. {
  552. removedChunksCs.unlock();
  553. return 1;
  554. }
  555. }
  556. removedChunksCs.unlock();
  557. return 0;
  558. }
  559. bool Dimension::reviveChunk(int x, int y)
  560. {
  561. chunkCs.lock();
  562. if (zChunk(Punkt(x, y)))
  563. {
  564. chunkCs.unlock();
  565. return 1;
  566. }
  567. removedChunksCs.lock();
  568. int index = 0;
  569. for (Iterator<Chunk*> i = removedChunks.begin(); i; i++)
  570. {
  571. if (i->getCenter().x == x && i->getCenter().y == y)
  572. {
  573. setChunk(dynamic_cast<Chunk*>(i->getThis()), Punkt(x, y));
  574. if (index > 0) i.remove();
  575. removedChunksCs.unlock();
  576. chunkCs.unlock();
  577. return 1;
  578. }
  579. index++;
  580. }
  581. removedChunksCs.unlock();
  582. chunkCs.unlock();
  583. return 0;
  584. }
  585. float Dimension::getGravity() const
  586. {
  587. return gravity;
  588. }
  589. void Dimension::removeOldChunks()
  590. {
  591. chunkCs.lock();
  592. int index = 0;
  593. for (Chunk* chunk : chunkList)
  594. {
  595. if (!chunk->hasObservers()) setChunk(0, chunk->getCenter());
  596. index++;
  597. }
  598. chunkCs.unlock();
  599. structurCs.lock();
  600. Iterator<MultiblockStructure*> i = structures.begin();
  601. while (i)
  602. {
  603. if (i->isEmpty())
  604. {
  605. i.remove();
  606. continue;
  607. }
  608. else if (i->isFullyUnloaded())
  609. {
  610. saveStructure(i);
  611. i.remove();
  612. continue;
  613. }
  614. i++;
  615. }
  616. structurCs.unlock();
  617. }
  618. Entity* Dimension::zEntity(int id)
  619. {
  620. for (auto entity : *entities)
  621. {
  622. if (!entity->isRemoved() && entity->getId() == id) return entity;
  623. }
  624. return 0;
  625. }
  626. Entity* Dimension::zNearestEntity(
  627. Framework::Vec3<float> pos, std::function<bool(Entity*)> filter)
  628. {
  629. Entity* result = 0;
  630. float sqDist = 0;
  631. for (auto entity : *entities)
  632. {
  633. if (!entity->isRemoved() && filter(entity))
  634. {
  635. float d = pos.abstandSq(entity->getPosition());
  636. if (!result || d < sqDist)
  637. {
  638. result = entity;
  639. sqDist = d;
  640. }
  641. }
  642. }
  643. return result;
  644. }
  645. void Dimension::removeEntity(int id)
  646. {
  647. int index = 0;
  648. for (auto entity : *entities)
  649. {
  650. if (entity->getId() == id)
  651. {
  652. entities->remove(index);
  653. return;
  654. }
  655. index++;
  656. }
  657. }
  658. void Dimension::removeSubscriptions(Entity* zEntity)
  659. {
  660. for (Chunk* chunk : chunkList)
  661. chunk->removeObserver(zEntity);
  662. }
  663. void Dimension::updateLightning(Vec3<int> location)
  664. {
  665. lightCs.lock();
  666. lightUpdateQueue.add(location, 0);
  667. lightCs.unlock();
  668. }
  669. void Dimension::updateLightningWithoutWait(Framework::Vec3<int> location)
  670. {
  671. prioLightCs.lock();
  672. priorizedLightUpdateQueue.add(location, 0);
  673. prioLightCs.unlock();
  674. }
  675. void Dimension::updateLightAtChunkBorders(Punkt chunkCenter)
  676. {
  677. if (lightUpdateQueue.getEintragAnzahl() > 300000)
  678. {
  679. std::cout
  680. << "warning: light calculation queue is over 300000 blocks long\n";
  681. }
  682. for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
  683. {
  684. for (int j = 0; j < CHUNK_SIZE; j++)
  685. {
  686. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 - 1,
  687. chunkCenter.y - CHUNK_SIZE / 2 + j,
  688. i));
  689. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2,
  690. chunkCenter.y - CHUNK_SIZE / 2 + j,
  691. i));
  692. updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2 - 1,
  693. chunkCenter.y - CHUNK_SIZE / 2 + j,
  694. i));
  695. updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2,
  696. chunkCenter.y - CHUNK_SIZE / 2 + j,
  697. i));
  698. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
  699. chunkCenter.y - CHUNK_SIZE / 2 - 1,
  700. i));
  701. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
  702. chunkCenter.y - CHUNK_SIZE / 2,
  703. i));
  704. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
  705. chunkCenter.y + CHUNK_SIZE / 2 - 1,
  706. i));
  707. updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
  708. chunkCenter.y + CHUNK_SIZE / 2,
  709. i));
  710. }
  711. }
  712. }
  713. __int64 Dimension::getNextStructureId()
  714. {
  715. return nextStructureId++;
  716. }
  717. void Dimension::addStructure(MultiblockStructure* structure)
  718. {
  719. structurCs.lock();
  720. structures.add(structure);
  721. structurCs.unlock();
  722. }
  723. MultiblockStructure* Dimension::zStructureByPosition(
  724. Framework::Vec3<int> uniquePosition)
  725. {
  726. structurCs.lock();
  727. for (MultiblockStructure* str : structures)
  728. {
  729. if (str->getUniquePosition() == uniquePosition)
  730. {
  731. structurCs.unlock();
  732. return str;
  733. }
  734. }
  735. // search for structure file
  736. Datei dir(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
  737. + "/structures");
  738. RCArray<Text>* names = dir.getDateiListe();
  739. if (names)
  740. {
  741. Vec3<int> uPos;
  742. for (Text* name : *names)
  743. {
  744. Datei d(Text(dir.zPfad()->getText()) + "/" + name->getText());
  745. if (d.open(Datei::Style::lesen))
  746. {
  747. d.lese((char*)&uPos.x, 4);
  748. d.lese((char*)&uPos.y, 4);
  749. d.lese((char*)&uPos.z, 4);
  750. if (uPos == uniquePosition)
  751. {
  752. int type;
  753. d.lese((char*)&type, 4);
  754. __int64 strId;
  755. d.lese((char*)&strId, 8);
  756. MultiblockStructure* str
  757. = StaticRegistry<MultiblockStructureType>::INSTANCE
  758. .zElement(type)
  759. ->loadStructure(
  760. dimensionId, strId, uniquePosition, &d);
  761. d.close();
  762. structures.add(str);
  763. names->release();
  764. structurCs.unlock();
  765. return str;
  766. }
  767. d.close();
  768. }
  769. }
  770. names->release();
  771. }
  772. structurCs.unlock();
  773. return 0;
  774. }
  775. MultiblockStructure* Dimension::zStructureById(__int64 id)
  776. {
  777. structurCs.lock();
  778. for (MultiblockStructure* str : structures)
  779. {
  780. if (str->getStructureId() == id)
  781. {
  782. structurCs.unlock();
  783. return str;
  784. }
  785. }
  786. // search for structure file
  787. Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
  788. + Text(dimensionId) + "/structures/";
  789. path.appendHex(id);
  790. path += ".str";
  791. Datei d(path);
  792. Vec3<int> uPos;
  793. if (d.open(Datei::Style::lesen))
  794. {
  795. d.lese((char*)&uPos.x, 4);
  796. d.lese((char*)&uPos.y, 4);
  797. d.lese((char*)&uPos.z, 4);
  798. int type;
  799. d.lese((char*)&type, 4);
  800. __int64 strId;
  801. d.lese((char*)&strId, 8);
  802. MultiblockStructure* str
  803. = StaticRegistry<MultiblockStructureType>::INSTANCE.zElement(type)
  804. ->loadStructure(dimensionId, strId, uPos, &d);
  805. d.close();
  806. structures.add(str);
  807. structurCs.unlock();
  808. return str;
  809. }
  810. std::cout << "WARNING: did not find Structure information file '" << path
  811. << "'.\n";
  812. structurCs.unlock();
  813. return 0;
  814. }
  815. void Dimension::requestStopAndWait()
  816. {
  817. stop = 1;
  818. warteAufThread(1000000);
  819. }
  820. void Dimension::updateMap(int x, int y, int height)
  821. {
  822. chunkCs.lock();
  823. int h1 = height % 2 == 0 ? height : height - 1;
  824. int h2 = h1 + 1;
  825. const Block* b1 = zBlockOrDefault({x, y, h1});
  826. const Block* b2 = zBlockOrDefault({x, y, h2});
  827. bool visible = 1;
  828. if (h2 != WORLD_HEIGHT - 1)
  829. {
  830. const Block* b3 = zBlockOrDefault({x, y, h2 + 1});
  831. visible = b3->isPassable() || b3->isTransparent();
  832. }
  833. int color1
  834. = (b2->isPassable() || b2->isTransparent()) ? b1->getMapColor() : 0;
  835. int color2 = visible ? b2->getMapColor() : 0;
  836. int color1m = 0;
  837. int color2m = 0;
  838. if (h1 > 0)
  839. {
  840. const Block* b1m = zBlockOrDefault({x, y, h1 - 2});
  841. const Block* b2m = zBlockOrDefault({x, y, h1 - 1});
  842. color1m = (b2m->isPassable() || b2m->isTransparent())
  843. ? b1m->getMapColor()
  844. : 0;
  845. color2m = (b1->isPassable() || b1->isTransparent()) ? b2m->getMapColor()
  846. : 0;
  847. }
  848. char addr[8];
  849. Punkt center = Game::INSTANCE->getChunkCenter(x, y);
  850. getAddrOfWorld(center, addr);
  851. ChunkMap* cMap = map->getMap(addr, 8, center);
  852. if (cMap)
  853. {
  854. Framework::Vec3<int> chunkLocation = chunkCoordinates({x, y, height});
  855. if (cMap->update((char)chunkLocation.x,
  856. (char)chunkLocation.y,
  857. (unsigned char)(chunkLocation.z / 2),
  858. color1,
  859. color2)
  860. || (h1 > 0
  861. && cMap->update((char)chunkLocation.x,
  862. (char)chunkLocation.y,
  863. (unsigned char)(chunkLocation.z / 2) - 1,
  864. color1m,
  865. color2m)))
  866. {
  867. map->onMapUpdated(addr, 8);
  868. }
  869. }
  870. chunkCs.unlock();
  871. }
  872. int Dimension::getChunkCount()
  873. {
  874. return chunkList.getEintragAnzahl();
  875. }