Dimension.cpp 27 KB

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