Dimension.cpp 30 KB

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