Dimension.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. #include "Dimension.h"
  2. #include <AsynchronCall.h>
  3. #include <Logging.h>
  4. #include "ChunkMap.h"
  5. #include "Constants.h"
  6. #include "DimensionMap.h"
  7. #include "Entity.h"
  8. #include "EntityType.h"
  9. #include "File.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. File d;
  32. d.setFile(
  33. Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(id) + "/meta.dim");
  34. if (d.exists())
  35. {
  36. d.open(File::Style::read);
  37. d.read((char*)&nextStructureId, 8);
  38. d.read((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->read(&type, 1);
  65. switch (type)
  66. {
  67. case 0: // chunk message
  68. {
  69. Point center;
  70. zRequest->read((char*)&center.x, 4);
  71. zRequest->read((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->read((char*)&location.x, 4);
  98. zRequest->read((char*)&location.y, 4);
  99. zRequest->read((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. Timer messer;
  129. messer.measureStart();
  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.getEntryCount())
  138. {
  139. position = internalLightUpdateQueue.get(0);
  140. internalLightUpdateQueue.remove(0);
  141. }
  142. else
  143. {
  144. removedChunksCs.lock();
  145. if (removedChunks.getEntryCount() > 0)
  146. {
  147. Chunk* removedChunk = removedChunks.z(0);
  148. removedChunksCs.unlock();
  149. Array<Framework::Point> 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. File d;
  157. d.setFile(filePath);
  158. d.create();
  159. d.open(File::Style::write);
  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.getEntryCount() > 0)
  168. {
  169. Point 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. File d;
  181. d.setFile(filePath);
  182. d.create();
  183. d.open(File::Style::write);
  184. c->save(&d, chunksToSave);
  185. d.close();
  186. }
  187. }
  188. }
  189. removedChunksCs.unlock();
  190. if (priorizedLightUpdateQueue.getEntryCount())
  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.getEntryCount())
  201. {
  202. messer.measureEnd();
  203. time += messer.getSekunden();
  204. Sleep(500);
  205. messer.measureStart();
  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.measureEnd();
  287. time += messer.getSekunden();
  288. Logging::debug()
  289. << "100000 light updates needed " << time << " seconds";
  290. time = 0;
  291. index = 0;
  292. messer.measureStart();
  293. }
  294. }
  295. Logging::info() << Text("Dimension ") + this->getDimensionId()
  296. + " update Thread exited.";
  297. }
  298. void Dimension::getAddrOf(Point cPos, char* addr) const
  299. {
  300. *(int*)addr = cPos.x;
  301. *((int*)addr + 1) = cPos.y;
  302. }
  303. void Dimension::getAddrOfWorld(Point 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. Timer zm;
  319. double ausgleich = 0.0;
  320. zm.measureStart();
  321. Sleep(16);
  322. while (!stop)
  323. {
  324. zm.measureEnd();
  325. double seconds = zm.getSekunden();
  326. zm.measureStart();
  327. {
  328. Framework::CriticalLock lock({&entityCs, &chunkCs});
  329. auto iterator = entities->begin();
  330. auto end = entities->end();
  331. while (iterator != end)
  332. {
  333. if (!iterator->isRemoved())
  334. {
  335. iterator->prepareTick(this, seconds);
  336. iterator++;
  337. }
  338. else
  339. {
  340. auto chunk = zChunk(
  341. Game::getChunkCenter((int)iterator->getPosition().x,
  342. (int)iterator->getPosition().y));
  343. if (chunk)
  344. {
  345. chunk->onEntityLeaves(iterator, 0);
  346. }
  347. iterator.remove();
  348. }
  349. }
  350. int index = 0;
  351. for (auto entity : *entities)
  352. {
  353. if (!entity->isRemoved())
  354. {
  355. entity->tick(this, seconds);
  356. }
  357. index++;
  358. }
  359. } // end of LOCK entityCs, chunkCs
  360. ausgleich += 1.0 / 30 - seconds;
  361. if (ausgleich > 0) Sleep((int)(ausgleich * 1000));
  362. }
  363. }
  364. Chunk* Dimension::zChunk(Point wPos) const
  365. {
  366. char addr[8];
  367. getAddrOfWorld(wPos, addr);
  368. return chunks->z(addr, 8);
  369. }
  370. Framework::Either<Block*, int> Dimension::zBlock(
  371. Vec3<int> location, OUT Chunk** zChunk) const
  372. {
  373. Chunk* c
  374. = this->zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  375. if (zChunk)
  376. {
  377. *zChunk = c;
  378. }
  379. if (c)
  380. {
  381. location = chunkCoordinates(location);
  382. return c->zBlockAt(location);
  383. }
  384. return 0;
  385. }
  386. Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location) const
  387. {
  388. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  389. if (c)
  390. {
  391. location = chunkCoordinates(location);
  392. c->instantiateBlock(location);
  393. auto result = c->zBlockAt(location);
  394. return result.isA() ? result.getA() : 0;
  395. }
  396. return 0;
  397. }
  398. const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location) const
  399. {
  400. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  401. if (c)
  402. {
  403. location = chunkCoordinates(location);
  404. return c->zBlockConst(location);
  405. }
  406. return &NoBlock::INSTANCE;
  407. }
  408. int Dimension::getBlockType(Framework::Vec3<int> location) const
  409. {
  410. Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
  411. if (c)
  412. {
  413. location = chunkCoordinates(location);
  414. return c->getBlockTypeAt(location);
  415. }
  416. return BlockTypeEnum::NO_BLOCK;
  417. }
  418. void Dimension::placeBlock(
  419. Framework::Vec3<int> location, Framework::Either<Block*, int> block)
  420. {
  421. if (block.isB() && block.getB() == BlockTypeEnum::NO_BLOCK) return;
  422. Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
  423. if (c)
  424. {
  425. location = chunkCoordinates(location);
  426. if (block.isA())
  427. c->putBlockAt(location, block);
  428. else
  429. {
  430. c->putBlockAt(location, 0);
  431. c->putBlockTypeAt(location, block);
  432. }
  433. }
  434. else if (block.isA())
  435. block.getA()->release();
  436. }
  437. void Dimension::sendBlockInfo(Framework::Vec3<int> location)
  438. {
  439. Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
  440. if (c)
  441. {
  442. location = chunkCoordinates(location);
  443. c->sendBlockInfo(location);
  444. }
  445. }
  446. void Dimension::addEntity(Entity* entity)
  447. {
  448. entityCs.lock();
  449. entities->add(entity);
  450. entityCs.unlock();
  451. }
  452. void Dimension::setChunk(Chunk* chunk, Point center)
  453. {
  454. char addr[8];
  455. getAddrOfWorld(center, addr);
  456. if (chunk) map->loadMap(addr, 8, chunk);
  457. chunkCs.lock();
  458. Chunk* old = chunks->get(addr, 8);
  459. if (old)
  460. {
  461. Game::INSTANCE->zTickOrganizer()->removeTickSource(old);
  462. old->prepareRemove();
  463. for (int i = 0; i < chunkList.getEntryCount(); i++)
  464. {
  465. if (chunkList.get(i) == old)
  466. {
  467. chunkList.remove(i);
  468. break;
  469. }
  470. }
  471. for (Entity* entity : old->getEntitiesInChunk())
  472. {
  473. removeEntity(entity->getId());
  474. }
  475. }
  476. chunks->set(addr, 8, chunk);
  477. if (chunk)
  478. {
  479. chunkList.add(chunk);
  480. }
  481. getAddrOfWorld(center + Point(CHUNK_SIZE, 0), addr);
  482. Chunk* zChunk = chunks->z(addr, 8);
  483. if (zChunk)
  484. {
  485. zChunk->setNeighbor(WEST, chunk);
  486. if (chunk)
  487. {
  488. chunk->setNeighbor(EAST, zChunk);
  489. Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
  490. }
  491. }
  492. getAddrOfWorld(center + Point(-CHUNK_SIZE, 0), addr);
  493. zChunk = chunks->z(addr, 8);
  494. if (zChunk)
  495. {
  496. zChunk->setNeighbor(EAST, chunk);
  497. if (chunk)
  498. {
  499. chunk->setNeighbor(WEST, zChunk);
  500. Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
  501. }
  502. }
  503. getAddrOfWorld(center + Point(0, CHUNK_SIZE), addr);
  504. zChunk = chunks->z(addr, 8);
  505. if (zChunk)
  506. {
  507. zChunk->setNeighbor(NORTH, chunk);
  508. if (chunk)
  509. {
  510. chunk->setNeighbor(SOUTH, zChunk);
  511. Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
  512. }
  513. }
  514. getAddrOfWorld(center + Point(0, -CHUNK_SIZE), addr);
  515. zChunk = chunks->z(addr, 8);
  516. if (zChunk)
  517. {
  518. zChunk->setNeighbor(SOUTH, chunk);
  519. if (chunk)
  520. {
  521. chunk->setNeighbor(NORTH, zChunk);
  522. Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
  523. }
  524. }
  525. DoLaterHandler laterHandler;
  526. if (chunk)
  527. {
  528. chunkCs.unlock();
  529. Game::INSTANCE->zGenerator()->postprocessChunk(chunk);
  530. chunk->setAdded();
  531. for (Entity* entity : chunk->getEntitiesInChunk())
  532. {
  533. addEntity(dynamic_cast<Entity*>(entity->getThis()));
  534. }
  535. cs.lock();
  536. int index = 0;
  537. for (ArrayIterator<RequestQueue> iterator = waitingRequests.begin();
  538. iterator;)
  539. {
  540. Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
  541. if (zE)
  542. {
  543. if (iterator.val().chunkCenter == chunk->getCenter())
  544. {
  545. chunk->api(iterator.val().request, zE, laterHandler);
  546. iterator.val().request->release();
  547. iterator.remove();
  548. continue;
  549. }
  550. }
  551. else
  552. {
  553. iterator.val().request->release();
  554. iterator.remove();
  555. continue;
  556. }
  557. iterator++;
  558. index++;
  559. }
  560. cs.unlock();
  561. Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
  562. }
  563. else
  564. {
  565. chunkCs.unlock();
  566. }
  567. if (old)
  568. {
  569. old->onUnloaded();
  570. removedChunksCs.lock();
  571. removedChunks.add(old);
  572. removedChunksCs.unlock();
  573. }
  574. if (chunk) chunk->onLoaded();
  575. laterHandler.execute();
  576. if (chunk)
  577. {
  578. updateLightAtChunkBorders(chunk);
  579. chunk->updateLightSources();
  580. }
  581. }
  582. void Dimension::save(Text worldDir) const
  583. {
  584. File d;
  585. d.setFile(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
  586. + "/meta.dim");
  587. d.create();
  588. d.open(File::Style::write);
  589. d.write((char*)&nextStructureId, 8);
  590. d.write((char*)&currentDayTime, 8);
  591. d.close();
  592. Array<Framework::Point> otherChunks;
  593. for (auto chunk = chunkList.begin(); chunk; chunk++)
  594. {
  595. if (!chunk._) continue;
  596. File* file = new File();
  597. Text filePath = worldDir + "/dim/" + dimensionId + "/";
  598. filePath.appendHex(chunk->getCenter().x);
  599. filePath += "_";
  600. filePath.appendHex(chunk->getCenter().y);
  601. filePath += ".chunk";
  602. file->setFile(filePath);
  603. if (file->open(File::Style::write)) chunk->save(file, otherChunks);
  604. file->close();
  605. file->release();
  606. char addr[8];
  607. getAddrOfWorld(chunk->getCenter(), addr);
  608. map->saveMap(addr, 8);
  609. }
  610. // since all chunks were saved otherChunks can be ignored
  611. entityCs.lock();
  612. for (Entity* entity : *entities)
  613. {
  614. if (entity->zType()->getId() == EntityTypeEnum::PLAYER)
  615. {
  616. File pFile;
  617. pFile.setFile(
  618. worldDir + "/player/"
  619. + Game::INSTANCE->getPlayerId(((Player*)entity)->getName()));
  620. pFile.create();
  621. if (pFile.open(File::Style::write))
  622. {
  623. Game::INSTANCE->zEntityType(EntityTypeEnum::PLAYER)
  624. ->saveEntity(entity, &pFile);
  625. pFile.close();
  626. }
  627. }
  628. }
  629. entityCs.unlock();
  630. for (MultiblockStructure* structure : structures)
  631. {
  632. saveStructure(structure);
  633. }
  634. }
  635. int Dimension::getDimensionId() const
  636. {
  637. return dimensionId;
  638. }
  639. bool Dimension::hasChunck(int x, int y) const
  640. {
  641. if (zChunk(Point(x, y))) return 1;
  642. removedChunksCs.lock();
  643. for (Chunk* c : removedChunks)
  644. {
  645. if (c->getCenter().x == x && c->getCenter().y == y)
  646. {
  647. removedChunksCs.unlock();
  648. return 1;
  649. }
  650. }
  651. removedChunksCs.unlock();
  652. return 0;
  653. }
  654. bool Dimension::reviveChunk(int x, int y)
  655. {
  656. chunkCs.lock();
  657. if (zChunk(Point(x, y)))
  658. {
  659. chunkCs.unlock();
  660. return 1;
  661. }
  662. removedChunksCs.lock();
  663. int index = 0;
  664. for (ArrayIterator<Chunk*> i = removedChunks.begin(); i; i++)
  665. {
  666. if (i->getCenter().x == x && i->getCenter().y == y)
  667. {
  668. setChunk(dynamic_cast<Chunk*>(i->getThis()), Point(x, y));
  669. if (index > 0) i.remove();
  670. removedChunksCs.unlock();
  671. chunkCs.unlock();
  672. return 1;
  673. }
  674. index++;
  675. }
  676. removedChunksCs.unlock();
  677. chunkCs.unlock();
  678. return 0;
  679. }
  680. float Dimension::getGravity() const
  681. {
  682. return gravity;
  683. }
  684. void Dimension::removeOldChunks()
  685. {
  686. chunkCs.lock();
  687. int index = 0;
  688. for (Chunk* chunk : chunkList)
  689. {
  690. if (!chunk->hasObservers()) setChunk(0, chunk->getCenter());
  691. index++;
  692. }
  693. chunkCs.unlock();
  694. structurCs.lock();
  695. ArrayIterator<MultiblockStructure*> i = structures.begin();
  696. while (i)
  697. {
  698. if (i->isEmpty())
  699. {
  700. i.remove();
  701. continue;
  702. }
  703. else if (i->isFullyUnloaded())
  704. {
  705. saveStructure(i);
  706. i.remove();
  707. continue;
  708. }
  709. i++;
  710. }
  711. structurCs.unlock();
  712. }
  713. Entity* Dimension::zTarget(Framework::Vec3<float> pos,
  714. Vec3<float> direction,
  715. float maxDistanceSq) const
  716. {
  717. double minDist = 0;
  718. Entity* closestEntity = 0;
  719. entityCs.lock();
  720. for (auto entity : *entities)
  721. {
  722. if (!entity->isRemoved()
  723. && entity->getPosition().distanceSq(pos) <= maxDistanceSq)
  724. {
  725. double dist = entity->getHitDistance(pos, direction);
  726. if (!isnan(dist))
  727. {
  728. if (!closestEntity || dist < minDist)
  729. {
  730. closestEntity = entity;
  731. minDist = dist;
  732. }
  733. }
  734. }
  735. }
  736. entityCs.unlock();
  737. return closestEntity;
  738. }
  739. Entity* Dimension::zEntity(int id) const
  740. {
  741. entityCs.lock();
  742. for (auto entity : *entities)
  743. {
  744. if (!entity->isRemoved() && entity->getId() == id)
  745. {
  746. entityCs.unlock();
  747. return entity;
  748. }
  749. }
  750. entityCs.unlock();
  751. return 0;
  752. }
  753. Entity* Dimension::zNearestEntity(
  754. Framework::Vec3<float> pos, std::function<bool(Entity*)> filter) const
  755. {
  756. Entity* result = 0;
  757. float sqDist = 0;
  758. entityCs.lock();
  759. for (auto entity : *entities)
  760. {
  761. if (!entity->isRemoved() && filter(entity))
  762. {
  763. float d = pos.distanceSq(entity->getPosition());
  764. if (!result || d < sqDist)
  765. {
  766. result = entity;
  767. sqDist = d;
  768. }
  769. }
  770. }
  771. entityCs.unlock();
  772. return result;
  773. }
  774. void Dimension::removeEntity(int id)
  775. {
  776. int index = 0;
  777. entityCs.lock();
  778. for (auto entity : *entities)
  779. {
  780. if (entity->getId() == id)
  781. {
  782. entities->remove(index);
  783. entityCs.unlock();
  784. return;
  785. }
  786. index++;
  787. }
  788. entityCs.unlock();
  789. }
  790. void Dimension::removeSubscriptions(Entity* zEntity)
  791. {
  792. for (Chunk* chunk : chunkList)
  793. chunk->removeObserver(zEntity);
  794. }
  795. void Dimension::updateLightning(Vec3<int> location)
  796. {
  797. lightCs.lock();
  798. lightUpdateQueue.add(location, 0);
  799. lightCs.unlock();
  800. }
  801. void Dimension::updateLightningWithoutWait(Framework::Vec3<int> location)
  802. {
  803. prioLightCs.lock();
  804. priorizedLightUpdateQueue.add(location, 0);
  805. prioLightCs.unlock();
  806. }
  807. void Dimension::updateLightAtChunkBorders(Chunk* zChunk)
  808. {
  809. if (lightUpdateQueue.getEntryCount() > 300000)
  810. {
  811. Logging::warning()
  812. << "light calculation queue is over 300000 blocks long";
  813. }
  814. Point center = zChunk->getCenter();
  815. Chunk* xn = this->zChunk(center - Point(CHUNK_SIZE, 0));
  816. Chunk* xp = this->zChunk(center + Point(CHUNK_SIZE, 0));
  817. Chunk* yn = this->zChunk(center - Point(0, CHUNK_SIZE));
  818. Chunk* yp = this->zChunk(center + Point(0, CHUNK_SIZE));
  819. for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
  820. {
  821. for (int j = 0; j < CHUNK_SIZE; j++)
  822. {
  823. if (xn)
  824. {
  825. unsigned char* light
  826. = xn->getLightData(Vec3<int>(CHUNK_SIZE - 1, j, i));
  827. unsigned char* light2
  828. = zChunk->getLightData(Vec3<int>(0, 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 (xp)
  841. {
  842. unsigned char* light = xp->getLightData(Vec3<int>(0, j, i));
  843. unsigned char* light2
  844. = zChunk->getLightData(Vec3<int>(CHUNK_SIZE - 1, j, i));
  845. if (*(int*)light != *(int*)light2
  846. || *(int*)(light + 2) != *(int*)(light2 + 2))
  847. {
  848. updateLightning(Vec3<int>(center.x + CHUNK_SIZE / 2 - 1,
  849. center.y - CHUNK_SIZE / 2 + j,
  850. i));
  851. updateLightning(Vec3<int>(center.x + CHUNK_SIZE / 2,
  852. center.y - CHUNK_SIZE / 2 + j,
  853. i));
  854. }
  855. }
  856. if (yn)
  857. {
  858. unsigned char* light
  859. = yn->getLightData(Vec3<int>(j, CHUNK_SIZE - 1, i));
  860. unsigned char* light2
  861. = zChunk->getLightData(Vec3<int>(j, 0, 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. if (yp)
  874. {
  875. unsigned char* light = yp->getLightData(Vec3<int>(j, 0, i));
  876. unsigned char* light2
  877. = zChunk->getLightData(Vec3<int>(j, CHUNK_SIZE - 1, i));
  878. if (*(int*)light != *(int*)light2
  879. || *(int*)(light + 2) != *(int*)(light2 + 2))
  880. {
  881. updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
  882. center.y + CHUNK_SIZE / 2 - 1,
  883. i));
  884. updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
  885. center.y + CHUNK_SIZE / 2,
  886. i));
  887. }
  888. }
  889. }
  890. }
  891. }
  892. __int64 Dimension::getNextStructureId()
  893. {
  894. return nextStructureId++;
  895. }
  896. void Dimension::addStructure(MultiblockStructure* structure)
  897. {
  898. structurCs.lock();
  899. structures.add(structure);
  900. structurCs.unlock();
  901. }
  902. MultiblockStructure* Dimension::zStructureByPosition(
  903. Framework::Vec3<int> uniquePosition)
  904. {
  905. __int64 id = structureManager->getStructureId(uniquePosition);
  906. if (id > 0)
  907. {
  908. return zStructureById(id);
  909. }
  910. return 0;
  911. }
  912. MultiblockStructure* Dimension::zStructureById(__int64 id)
  913. {
  914. structurCs.lock();
  915. for (MultiblockStructure* str : structures)
  916. {
  917. if (str->getStructureId() == id)
  918. {
  919. structurCs.unlock();
  920. return str;
  921. }
  922. }
  923. MultiblockStructure* structure = structureManager->loadStructure(id);
  924. if (structure)
  925. {
  926. structures.add(structure);
  927. structurCs.unlock();
  928. return structure;
  929. }
  930. Logging::warning() << "did not find Structure information file '"
  931. << std::hex << id << "'.";
  932. structurCs.unlock();
  933. return 0;
  934. }
  935. void Dimension::requestStopAndWait()
  936. {
  937. stop = 1;
  938. waitForThread(1000000);
  939. }
  940. void Dimension::updateMap(int x, int y, int height)
  941. {
  942. chunkCs.lock();
  943. int h1 = height % 2 == 0 ? height : height - 1;
  944. int h2 = h1 + 1;
  945. const Block* b1 = zBlockOrDefault({x, y, h1});
  946. const Block* b2 = zBlockOrDefault({x, y, h2});
  947. bool visible = 1;
  948. if (h2 != WORLD_HEIGHT - 1)
  949. {
  950. const Block* b3 = zBlockOrDefault({x, y, h2 + 1});
  951. visible = b3->isPassable() || b3->isTransparent();
  952. }
  953. int color1
  954. = (b2->isPassable() || b2->isTransparent()) ? b1->getMapColor() : 0;
  955. int color2 = visible ? b2->getMapColor() : 0;
  956. int color1m = 0;
  957. int color2m = 0;
  958. if (h1 > 0)
  959. {
  960. const Block* b1m = zBlockOrDefault({x, y, h1 - 2});
  961. const Block* b2m = zBlockOrDefault({x, y, h1 - 1});
  962. color1m = (b2m->isPassable() || b2m->isTransparent())
  963. ? b1m->getMapColor()
  964. : 0;
  965. color2m = (b1->isPassable() || b1->isTransparent()) ? b2m->getMapColor()
  966. : 0;
  967. }
  968. char addr[8];
  969. Point center = Game::INSTANCE->getChunkCenter(x, y);
  970. getAddrOfWorld(center, addr);
  971. ChunkMap* cMap = map->getMap(addr, 8, center);
  972. if (cMap)
  973. {
  974. Framework::Vec3<int> chunkLocation = chunkCoordinates({x, y, height});
  975. if (cMap->update((char)chunkLocation.x,
  976. (char)chunkLocation.y,
  977. (unsigned char)(chunkLocation.z / 2),
  978. color1,
  979. color2)
  980. || (h1 > 0
  981. && cMap->update((char)chunkLocation.x,
  982. (char)chunkLocation.y,
  983. (unsigned char)(chunkLocation.z / 2 - 1),
  984. color1m,
  985. color2m)))
  986. {
  987. map->onMapUpdated(addr, 8);
  988. }
  989. }
  990. chunkCs.unlock();
  991. }
  992. int Dimension::getChunkCount() const
  993. {
  994. return chunkList.getEntryCount();
  995. }
  996. double Dimension::getCurrentDayTime() const
  997. {
  998. return currentDayTime;
  999. }
  1000. double Dimension::getNightDuration() const
  1001. {
  1002. return nightDuration;
  1003. }
  1004. double Dimension::getNightTransitionDuration() const
  1005. {
  1006. return nightTransitionDuration;
  1007. }
  1008. double Dimension::getDayDuration() const
  1009. {
  1010. return dayDuration;
  1011. }