map.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "map.h"
  17. #include "mapsector.h"
  18. #include "mapblock.h"
  19. #include "voxel.h"
  20. #include "voxelalgorithms.h"
  21. #include "porting.h"
  22. #include "nodemetadata.h"
  23. #include "log.h"
  24. #include "profiler.h"
  25. #include "nodedef.h"
  26. #include "gamedef.h"
  27. #include "util/directiontables.h"
  28. #include "rollback_interface.h"
  29. #include "environment.h"
  30. #include "irrlicht_changes/printing.h"
  31. /*
  32. Map
  33. */
  34. Map::Map(IGameDef *gamedef):
  35. m_gamedef(gamedef),
  36. m_nodedef(gamedef->ndef())
  37. {
  38. }
  39. Map::~Map()
  40. {
  41. /*
  42. Free all MapSectors
  43. */
  44. for (auto &sector : m_sectors) {
  45. delete sector.second;
  46. }
  47. }
  48. void Map::addEventReceiver(MapEventReceiver *event_receiver)
  49. {
  50. m_event_receivers.insert(event_receiver);
  51. }
  52. void Map::removeEventReceiver(MapEventReceiver *event_receiver)
  53. {
  54. m_event_receivers.erase(event_receiver);
  55. }
  56. void Map::dispatchEvent(const MapEditEvent &event)
  57. {
  58. for (MapEventReceiver *event_receiver : m_event_receivers) {
  59. event_receiver->onMapEditEvent(event);
  60. }
  61. }
  62. MapSector * Map::getSectorNoGenerateNoLock(v2s16 p)
  63. {
  64. if(m_sector_cache != NULL && p == m_sector_cache_p){
  65. MapSector * sector = m_sector_cache;
  66. return sector;
  67. }
  68. auto n = m_sectors.find(p);
  69. if (n == m_sectors.end())
  70. return NULL;
  71. MapSector *sector = n->second;
  72. // Cache the last result
  73. m_sector_cache_p = p;
  74. m_sector_cache = sector;
  75. return sector;
  76. }
  77. MapSector *Map::getSectorNoGenerate(v2s16 p)
  78. {
  79. return getSectorNoGenerateNoLock(p);
  80. }
  81. MapBlock *Map::getBlockNoCreateNoEx(v3s16 p3d)
  82. {
  83. v2s16 p2d(p3d.X, p3d.Z);
  84. MapSector *sector = getSectorNoGenerate(p2d);
  85. if (!sector)
  86. return nullptr;
  87. MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
  88. return block;
  89. }
  90. MapBlock *Map::getBlockNoCreate(v3s16 p3d)
  91. {
  92. MapBlock *block = getBlockNoCreateNoEx(p3d);
  93. if(block == NULL)
  94. throw InvalidPositionException();
  95. return block;
  96. }
  97. bool Map::isValidPosition(v3s16 p)
  98. {
  99. v3s16 blockpos = getNodeBlockPos(p);
  100. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  101. return (block != NULL);
  102. }
  103. // Returns a CONTENT_IGNORE node if not found
  104. MapNode Map::getNode(v3s16 p, bool *is_valid_position)
  105. {
  106. v3s16 blockpos = getNodeBlockPos(p);
  107. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  108. if (block == NULL) {
  109. if (is_valid_position != NULL)
  110. *is_valid_position = false;
  111. return {CONTENT_IGNORE};
  112. }
  113. v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
  114. MapNode node = block->getNodeNoCheck(relpos);
  115. if (is_valid_position != NULL)
  116. *is_valid_position = true;
  117. return node;
  118. }
  119. static void set_node_in_block(const NodeDefManager *nodedef, MapBlock *block,
  120. v3s16 relpos, MapNode n)
  121. {
  122. // Never allow placing CONTENT_IGNORE, it causes problems
  123. if(n.getContent() == CONTENT_IGNORE){
  124. v3s16 blockpos = block->getPos();
  125. v3s16 p = blockpos * MAP_BLOCKSIZE + relpos;
  126. errorstream<<"Not allowing to place CONTENT_IGNORE"
  127. <<" while trying to replace \""
  128. <<nodedef->get(block->getNodeNoCheck(relpos)).name
  129. <<"\" at "<<p<<" (block "<<blockpos<<")"<<std::endl;
  130. return;
  131. }
  132. block->setNodeNoCheck(relpos, n);
  133. }
  134. // throws InvalidPositionException if not found
  135. void Map::setNode(v3s16 p, MapNode n)
  136. {
  137. v3s16 blockpos = getNodeBlockPos(p);
  138. MapBlock *block = getBlockNoCreate(blockpos);
  139. v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
  140. set_node_in_block(m_gamedef->ndef(), block, relpos, n);
  141. }
  142. void Map::addNodeAndUpdate(v3s16 p, MapNode n,
  143. std::map<v3s16, MapBlock*> &modified_blocks,
  144. bool remove_metadata)
  145. {
  146. // Collect old node for rollback
  147. RollbackNode rollback_oldnode(this, p, m_gamedef);
  148. v3s16 blockpos = getNodeBlockPos(p);
  149. MapBlock *block = getBlockNoCreate(blockpos);
  150. v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
  151. // This is needed for updating the lighting
  152. MapNode oldnode = block->getNodeNoCheck(relpos);
  153. // Remove node metadata
  154. if (remove_metadata) {
  155. removeNodeMetadata(p);
  156. }
  157. // Set the node on the map
  158. ContentLightingFlags f = m_nodedef->getLightingFlags(n);
  159. ContentLightingFlags oldf = m_nodedef->getLightingFlags(oldnode);
  160. if (f == oldf) {
  161. // No light update needed, just copy over the old light.
  162. n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldf), f);
  163. n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldf), f);
  164. set_node_in_block(m_gamedef->ndef(), block, relpos, n);
  165. modified_blocks[blockpos] = block;
  166. } else {
  167. // Ignore light (because calling voxalgo::update_lighting_nodes)
  168. n.setLight(LIGHTBANK_DAY, 0, f);
  169. n.setLight(LIGHTBANK_NIGHT, 0, f);
  170. set_node_in_block(m_gamedef->ndef(), block, relpos, n);
  171. // Update lighting
  172. std::vector<std::pair<v3s16, MapNode> > oldnodes;
  173. oldnodes.emplace_back(p, oldnode);
  174. voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
  175. }
  176. if (n.getContent() != oldnode.getContent() &&
  177. (oldnode.getContent() == CONTENT_AIR || n.getContent() == CONTENT_AIR))
  178. block->expireIsAirCache();
  179. // Report for rollback
  180. if(m_gamedef->rollback())
  181. {
  182. RollbackNode rollback_newnode(this, p, m_gamedef);
  183. RollbackAction action;
  184. action.setSetNode(p, rollback_oldnode, rollback_newnode);
  185. m_gamedef->rollback()->reportAction(action);
  186. }
  187. }
  188. void Map::removeNodeAndUpdate(v3s16 p,
  189. std::map<v3s16, MapBlock*> &modified_blocks)
  190. {
  191. addNodeAndUpdate(p, MapNode(CONTENT_AIR), modified_blocks, true);
  192. }
  193. bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
  194. {
  195. MapEditEvent event;
  196. event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
  197. event.p = p;
  198. event.n = n;
  199. bool succeeded = true;
  200. try{
  201. std::map<v3s16, MapBlock*> modified_blocks;
  202. addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
  203. event.setModifiedBlocks(modified_blocks);
  204. }
  205. catch(InvalidPositionException &e){
  206. succeeded = false;
  207. }
  208. dispatchEvent(event);
  209. return succeeded;
  210. }
  211. bool Map::removeNodeWithEvent(v3s16 p)
  212. {
  213. MapEditEvent event;
  214. event.type = MEET_REMOVENODE;
  215. event.p = p;
  216. bool succeeded = true;
  217. try{
  218. std::map<v3s16, MapBlock*> modified_blocks;
  219. removeNodeAndUpdate(p, modified_blocks);
  220. event.setModifiedBlocks(modified_blocks);
  221. }
  222. catch(InvalidPositionException &e){
  223. succeeded = false;
  224. }
  225. dispatchEvent(event);
  226. return succeeded;
  227. }
  228. struct TimeOrderedMapBlock {
  229. MapSector *sect;
  230. MapBlock *block;
  231. TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
  232. sect(sect),
  233. block(block)
  234. {}
  235. bool operator<(const TimeOrderedMapBlock &b) const
  236. {
  237. return block->getUsageTimer() < b.block->getUsageTimer();
  238. };
  239. };
  240. /*
  241. Updates usage timers
  242. */
  243. void Map::timerUpdate(float dtime, float unload_timeout, s32 max_loaded_blocks,
  244. std::vector<v3s16> *unloaded_blocks)
  245. {
  246. bool save_before_unloading = maySaveBlocks();
  247. // Profile modified reasons
  248. Profiler modprofiler;
  249. std::vector<v2s16> sector_deletion_queue;
  250. u32 deleted_blocks_count = 0;
  251. u32 saved_blocks_count = 0;
  252. u32 block_count_all = 0;
  253. u32 locked_blocks = 0;
  254. const auto start_time = porting::getTimeUs();
  255. beginSave();
  256. // If there is no practical limit, we spare creation of mapblock_queue
  257. if (max_loaded_blocks < 0) {
  258. for (auto &sector_it : m_sectors) {
  259. MapSector *sector = sector_it.second;
  260. bool all_blocks_deleted = true;
  261. MapBlockVect blocks;
  262. sector->getBlocks(blocks);
  263. for (MapBlock *block : blocks) {
  264. block->incrementUsageTimer(dtime);
  265. if (block->refGet() == 0
  266. && block->getUsageTimer() > unload_timeout) {
  267. v3s16 p = block->getPos();
  268. // Save if modified
  269. if (block->getModified() != MOD_STATE_CLEAN
  270. && save_before_unloading) {
  271. modprofiler.add(block->getModifiedReasonString(), 1);
  272. if (!saveBlock(block))
  273. continue;
  274. saved_blocks_count++;
  275. }
  276. // Delete from memory
  277. sector->deleteBlock(block);
  278. if (unloaded_blocks)
  279. unloaded_blocks->push_back(p);
  280. deleted_blocks_count++;
  281. } else {
  282. all_blocks_deleted = false;
  283. block_count_all++;
  284. }
  285. }
  286. // Delete sector if we emptied it
  287. if (all_blocks_deleted) {
  288. sector_deletion_queue.push_back(sector_it.first);
  289. }
  290. }
  291. } else {
  292. std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
  293. for (auto &sector_it : m_sectors) {
  294. MapSector *sector = sector_it.second;
  295. MapBlockVect blocks;
  296. sector->getBlocks(blocks);
  297. for (MapBlock *block : blocks) {
  298. block->incrementUsageTimer(dtime);
  299. mapblock_queue.push(TimeOrderedMapBlock(sector, block));
  300. }
  301. }
  302. block_count_all = mapblock_queue.size();
  303. // Delete old blocks, and blocks over the limit from the memory
  304. while (!mapblock_queue.empty() && ((s32)mapblock_queue.size() > max_loaded_blocks
  305. || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
  306. TimeOrderedMapBlock b = mapblock_queue.top();
  307. mapblock_queue.pop();
  308. MapBlock *block = b.block;
  309. if (block->refGet() != 0) {
  310. locked_blocks++;
  311. continue;
  312. }
  313. v3s16 p = block->getPos();
  314. // Save if modified
  315. if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
  316. modprofiler.add(block->getModifiedReasonString(), 1);
  317. if (!saveBlock(block))
  318. continue;
  319. saved_blocks_count++;
  320. }
  321. // Delete from memory
  322. b.sect->deleteBlock(block);
  323. if (unloaded_blocks)
  324. unloaded_blocks->push_back(p);
  325. deleted_blocks_count++;
  326. block_count_all--;
  327. }
  328. // Delete empty sectors
  329. for (auto &sector_it : m_sectors) {
  330. if (sector_it.second->empty()) {
  331. sector_deletion_queue.push_back(sector_it.first);
  332. }
  333. }
  334. }
  335. endSave();
  336. const auto end_time = porting::getTimeUs();
  337. reportMetrics(end_time - start_time, saved_blocks_count, block_count_all);
  338. // Finally delete the empty sectors
  339. deleteSectors(sector_deletion_queue);
  340. if(deleted_blocks_count != 0)
  341. {
  342. PrintInfo(infostream); // ServerMap/ClientMap:
  343. infostream<<"Unloaded "<<deleted_blocks_count
  344. <<" blocks from memory";
  345. if(save_before_unloading)
  346. infostream<<", of which "<<saved_blocks_count<<" were written";
  347. infostream<<", "<<block_count_all<<" blocks in memory, " << locked_blocks << " locked";
  348. infostream<<"."<<std::endl;
  349. if(saved_blocks_count != 0){
  350. PrintInfo(infostream); // ServerMap/ClientMap:
  351. infostream<<"Blocks modified by: "<<std::endl;
  352. modprofiler.print(infostream);
  353. }
  354. }
  355. }
  356. void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
  357. {
  358. timerUpdate(0.0, -1.0, 0, unloaded_blocks);
  359. }
  360. void Map::deleteSectors(std::vector<v2s16> &sectorList)
  361. {
  362. for (v2s16 j : sectorList) {
  363. MapSector *sector = m_sectors[j];
  364. // If sector is in sector cache, remove it from there
  365. if(m_sector_cache == sector)
  366. m_sector_cache = NULL;
  367. // Remove from map and delete
  368. m_sectors.erase(j);
  369. delete sector;
  370. }
  371. }
  372. void Map::PrintInfo(std::ostream &out)
  373. {
  374. out<<"Map: ";
  375. }
  376. std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
  377. {
  378. std::vector<v3s16> positions_with_meta;
  379. sortBoxVerticies(p1, p2);
  380. v3s16 bpmin = getNodeBlockPos(p1);
  381. v3s16 bpmax = getNodeBlockPos(p2);
  382. VoxelArea area(p1, p2);
  383. for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
  384. for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
  385. for (s16 x = bpmin.X; x <= bpmax.X; x++) {
  386. v3s16 blockpos(x, y, z);
  387. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  388. if (!block) {
  389. verbosestream << "Map::getNodeMetadata(): Need to emerge "
  390. << blockpos << std::endl;
  391. block = emergeBlock(blockpos, false);
  392. }
  393. if (!block) {
  394. infostream << "WARNING: Map::getNodeMetadata(): Block not found"
  395. << std::endl;
  396. continue;
  397. }
  398. v3s16 p_base = blockpos * MAP_BLOCKSIZE;
  399. std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
  400. for (size_t i = 0; i != keys.size(); i++) {
  401. v3s16 p(keys[i] + p_base);
  402. if (!area.contains(p))
  403. continue;
  404. positions_with_meta.push_back(p);
  405. }
  406. }
  407. return positions_with_meta;
  408. }
  409. NodeMetadata *Map::getNodeMetadata(v3s16 p)
  410. {
  411. v3s16 blockpos = getNodeBlockPos(p);
  412. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  413. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  414. if(!block){
  415. infostream<<"Map::getNodeMetadata(): Need to emerge "
  416. <<blockpos<<std::endl;
  417. block = emergeBlock(blockpos, false);
  418. }
  419. if(!block){
  420. warningstream<<"Map::getNodeMetadata(): Block not found"
  421. <<std::endl;
  422. return NULL;
  423. }
  424. NodeMetadata *meta = block->m_node_metadata.get(p_rel);
  425. return meta;
  426. }
  427. bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
  428. {
  429. v3s16 blockpos = getNodeBlockPos(p);
  430. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  431. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  432. if(!block){
  433. infostream<<"Map::setNodeMetadata(): Need to emerge "
  434. <<blockpos<<std::endl;
  435. block = emergeBlock(blockpos, false);
  436. }
  437. if(!block){
  438. warningstream<<"Map::setNodeMetadata(): Block not found"
  439. <<std::endl;
  440. return false;
  441. }
  442. block->m_node_metadata.set(p_rel, meta);
  443. return true;
  444. }
  445. void Map::removeNodeMetadata(v3s16 p)
  446. {
  447. v3s16 blockpos = getNodeBlockPos(p);
  448. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  449. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  450. if(block == NULL)
  451. {
  452. warningstream<<"Map::removeNodeMetadata(): Block not found"
  453. <<std::endl;
  454. return;
  455. }
  456. block->m_node_metadata.remove(p_rel);
  457. }
  458. NodeTimer Map::getNodeTimer(v3s16 p)
  459. {
  460. v3s16 blockpos = getNodeBlockPos(p);
  461. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  462. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  463. if(!block){
  464. infostream<<"Map::getNodeTimer(): Need to emerge "
  465. <<blockpos<<std::endl;
  466. block = emergeBlock(blockpos, false);
  467. }
  468. if(!block){
  469. warningstream<<"Map::getNodeTimer(): Block not found"
  470. <<std::endl;
  471. return NodeTimer();
  472. }
  473. NodeTimer t = block->getNodeTimer(p_rel);
  474. NodeTimer nt(t.timeout, t.elapsed, p);
  475. return nt;
  476. }
  477. void Map::setNodeTimer(const NodeTimer &t)
  478. {
  479. v3s16 p = t.position;
  480. v3s16 blockpos = getNodeBlockPos(p);
  481. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  482. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  483. if(!block){
  484. infostream<<"Map::setNodeTimer(): Need to emerge "
  485. <<blockpos<<std::endl;
  486. block = emergeBlock(blockpos, false);
  487. }
  488. if(!block){
  489. warningstream<<"Map::setNodeTimer(): Block not found"
  490. <<std::endl;
  491. return;
  492. }
  493. NodeTimer nt(t.timeout, t.elapsed, p_rel);
  494. block->setNodeTimer(nt);
  495. }
  496. void Map::removeNodeTimer(v3s16 p)
  497. {
  498. v3s16 blockpos = getNodeBlockPos(p);
  499. v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
  500. MapBlock *block = getBlockNoCreateNoEx(blockpos);
  501. if(block == NULL)
  502. {
  503. warningstream<<"Map::removeNodeTimer(): Block not found"
  504. <<std::endl;
  505. return;
  506. }
  507. block->removeNodeTimer(p_rel);
  508. }
  509. bool Map::determineAdditionalOcclusionCheck(const v3s16 pos_camera,
  510. const core::aabbox3d<s16> &block_bounds, v3s16 &check)
  511. {
  512. /*
  513. This functions determines the node inside the target block that is
  514. closest to the camera position. This increases the occlusion culling
  515. accuracy in straight and diagonal corridors.
  516. The returned position will be occlusion checked first in addition to the
  517. others (8 corners + center).
  518. No position is returned if
  519. - the closest node is a corner, corners are checked anyway.
  520. - the camera is inside the target block, it will never be occluded.
  521. */
  522. #define CLOSEST_EDGE(pos, bounds, axis) \
  523. ((pos).axis <= (bounds).MinEdge.axis) ? (bounds).MinEdge.axis : \
  524. (bounds).MaxEdge.axis
  525. bool x_inside = (block_bounds.MinEdge.X <= pos_camera.X) &&
  526. (pos_camera.X <= block_bounds.MaxEdge.X);
  527. bool y_inside = (block_bounds.MinEdge.Y <= pos_camera.Y) &&
  528. (pos_camera.Y <= block_bounds.MaxEdge.Y);
  529. bool z_inside = (block_bounds.MinEdge.Z <= pos_camera.Z) &&
  530. (pos_camera.Z <= block_bounds.MaxEdge.Z);
  531. if (x_inside && y_inside && z_inside)
  532. return false; // Camera inside target mapblock
  533. // straight
  534. if (x_inside && y_inside) {
  535. check = v3s16(pos_camera.X, pos_camera.Y, 0);
  536. check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
  537. return true;
  538. } else if (y_inside && z_inside) {
  539. check = v3s16(0, pos_camera.Y, pos_camera.Z);
  540. check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
  541. return true;
  542. } else if (x_inside && z_inside) {
  543. check = v3s16(pos_camera.X, 0, pos_camera.Z);
  544. check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
  545. return true;
  546. }
  547. // diagonal
  548. if (x_inside) {
  549. check = v3s16(pos_camera.X, 0, 0);
  550. check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
  551. check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
  552. return true;
  553. } else if (y_inside) {
  554. check = v3s16(0, pos_camera.Y, 0);
  555. check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
  556. check.Z = CLOSEST_EDGE(pos_camera, block_bounds, Z);
  557. return true;
  558. } else if (z_inside) {
  559. check = v3s16(0, 0, pos_camera.Z);
  560. check.X = CLOSEST_EDGE(pos_camera, block_bounds, X);
  561. check.Y = CLOSEST_EDGE(pos_camera, block_bounds, Y);
  562. return true;
  563. }
  564. // Closest node would be a corner, none returned
  565. return false;
  566. }
  567. bool Map::isOccluded(const v3s16 pos_camera, const v3s16 pos_target,
  568. float step, float stepfac, float offset, float end_offset, u32 needed_count)
  569. {
  570. v3f direction = intToFloat(pos_target - pos_camera, BS);
  571. float distance = direction.getLength();
  572. // Normalize direction vector
  573. if (distance > 0.0f)
  574. direction /= distance;
  575. v3f pos_origin_f = intToFloat(pos_camera, BS);
  576. u32 count = 0;
  577. bool is_valid_position;
  578. for (; offset < distance + end_offset; offset += step) {
  579. v3f pos_node_f = pos_origin_f + direction * offset;
  580. v3s16 pos_node = floatToInt(pos_node_f, BS);
  581. MapNode node = getNode(pos_node, &is_valid_position);
  582. if (is_valid_position &&
  583. !m_nodedef->getLightingFlags(node).light_propagates) {
  584. // Cannot see through light-blocking nodes --> occluded
  585. count++;
  586. if (count >= needed_count)
  587. return true;
  588. }
  589. step *= stepfac;
  590. }
  591. return false;
  592. }
  593. bool Map::isBlockOccluded(v3s16 pos_relative, v3s16 cam_pos_nodes, bool simple_check)
  594. {
  595. // Check occlusion for center and all 8 corners of the mapblock
  596. // Overshoot a little for less flickering
  597. static const s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
  598. static const v3s16 dir9[9] = {
  599. v3s16( 0, 0, 0),
  600. v3s16( 1, 1, 1) * bs2,
  601. v3s16( 1, 1, -1) * bs2,
  602. v3s16( 1, -1, 1) * bs2,
  603. v3s16( 1, -1, -1) * bs2,
  604. v3s16(-1, 1, 1) * bs2,
  605. v3s16(-1, 1, -1) * bs2,
  606. v3s16(-1, -1, 1) * bs2,
  607. v3s16(-1, -1, -1) * bs2,
  608. };
  609. v3s16 pos_blockcenter = pos_relative + (MAP_BLOCKSIZE / 2);
  610. // Starting step size, value between 1m and sqrt(3)m
  611. float step = BS * 1.2f;
  612. // Multiply step by each iteraction by 'stepfac' to reduce checks in distance
  613. float stepfac = 1.05f;
  614. float start_offset = BS * 1.0f;
  615. // The occlusion search of 'isOccluded()' must stop short of the target
  616. // point by distance 'end_offset' to not enter the target mapblock.
  617. // For the 8 mapblock corners 'end_offset' must therefore be the maximum
  618. // diagonal of a mapblock, because we must consider all view angles.
  619. // sqrt(1^2 + 1^2 + 1^2) = 1.732
  620. float end_offset = -BS * MAP_BLOCKSIZE * 1.732f;
  621. // to reduce the likelihood of falsely occluded blocks
  622. // require at least two solid blocks
  623. // this is a HACK, we should think of a more precise algorithm
  624. u32 needed_count = 2;
  625. // This should be only used in server occlusion cullung.
  626. // The client recalculates the complete drawlist periodically,
  627. // and random sampling could lead to visible flicker.
  628. if (simple_check) {
  629. v3s16 random_point(myrand_range(-bs2, bs2), myrand_range(-bs2, bs2), myrand_range(-bs2, bs2));
  630. return isOccluded(cam_pos_nodes, pos_blockcenter + random_point, step, stepfac,
  631. start_offset, end_offset, 1);
  632. }
  633. // Additional occlusion check, see comments in that function
  634. v3s16 check;
  635. if (determineAdditionalOcclusionCheck(cam_pos_nodes, MapBlock::getBox(pos_relative), check)) {
  636. // node is always on a side facing the camera, end_offset can be lower
  637. if (!isOccluded(cam_pos_nodes, check, step, stepfac, start_offset,
  638. -1.0f, needed_count))
  639. return false;
  640. }
  641. for (const v3s16 &dir : dir9) {
  642. if (!isOccluded(cam_pos_nodes, pos_blockcenter + dir, step, stepfac,
  643. start_offset, end_offset, needed_count))
  644. return false;
  645. }
  646. return true;
  647. }
  648. MMVManip::MMVManip(Map *map):
  649. VoxelManipulator(),
  650. m_map(map)
  651. {
  652. assert(map);
  653. }
  654. void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
  655. bool load_if_inexistent)
  656. {
  657. TimeTaker timer1("initialEmerge", &emerge_time);
  658. assert(m_map);
  659. // Units of these are MapBlocks
  660. v3s16 p_min = blockpos_min;
  661. v3s16 p_max = blockpos_max;
  662. VoxelArea block_area_nodes
  663. (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
  664. u32 size_MB = block_area_nodes.getVolume()*4/1000000;
  665. if(size_MB >= 1)
  666. {
  667. infostream<<"initialEmerge: area: ";
  668. block_area_nodes.print(infostream);
  669. infostream<<" ("<<size_MB<<"MB)";
  670. infostream<<std::endl;
  671. }
  672. addArea(block_area_nodes);
  673. for(s32 z=p_min.Z; z<=p_max.Z; z++)
  674. for(s32 y=p_min.Y; y<=p_max.Y; y++)
  675. for(s32 x=p_min.X; x<=p_max.X; x++)
  676. {
  677. u8 flags = 0;
  678. MapBlock *block;
  679. v3s16 p(x,y,z);
  680. if (m_loaded_blocks.count(p) > 0)
  681. continue;
  682. bool block_data_inexistent = false;
  683. {
  684. TimeTaker timer2("emerge load", &emerge_load_time);
  685. block = m_map->getBlockNoCreateNoEx(p);
  686. if (!block)
  687. block_data_inexistent = true;
  688. else
  689. block->copyTo(*this);
  690. }
  691. if(block_data_inexistent)
  692. {
  693. if (load_if_inexistent && !blockpos_over_max_limit(p)) {
  694. block = m_map->emergeBlock(p, true);
  695. block->copyTo(*this);
  696. } else {
  697. flags |= VMANIP_BLOCK_DATA_INEXIST;
  698. /*
  699. Mark area inexistent
  700. */
  701. VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
  702. // Fill with VOXELFLAG_NO_DATA
  703. for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
  704. for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
  705. {
  706. s32 i = m_area.index(a.MinEdge.X,y,z);
  707. memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
  708. }
  709. }
  710. }
  711. /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
  712. {
  713. // Mark that block was loaded as blank
  714. flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
  715. }*/
  716. m_loaded_blocks[p] = flags;
  717. }
  718. m_is_dirty = false;
  719. }
  720. void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
  721. bool overwrite_generated)
  722. {
  723. if(m_area.getExtent() == v3s16(0,0,0))
  724. return;
  725. assert(m_map);
  726. /*
  727. Copy data of all blocks
  728. */
  729. for (auto &loaded_block : m_loaded_blocks) {
  730. v3s16 p = loaded_block.first;
  731. MapBlock *block = m_map->getBlockNoCreateNoEx(p);
  732. bool existed = !(loaded_block.second & VMANIP_BLOCK_DATA_INEXIST);
  733. if (!existed || (block == NULL) ||
  734. (!overwrite_generated && block->isGenerated()))
  735. continue;
  736. block->copyFrom(*this);
  737. block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
  738. block->expireIsAirCache();
  739. if(modified_blocks)
  740. (*modified_blocks)[p] = block;
  741. }
  742. }
  743. MMVManip *MMVManip::clone() const
  744. {
  745. MMVManip *ret = new MMVManip();
  746. const s32 size = m_area.getVolume();
  747. ret->m_area = m_area;
  748. if (m_data) {
  749. ret->m_data = new MapNode[size];
  750. memcpy(ret->m_data, m_data, size * sizeof(MapNode));
  751. }
  752. if (m_flags) {
  753. ret->m_flags = new u8[size];
  754. memcpy(ret->m_flags, m_flags, size * sizeof(u8));
  755. }
  756. ret->m_is_dirty = m_is_dirty;
  757. // Even if the copy is disconnected from a map object keep the information
  758. // needed to write it back to one
  759. ret->m_loaded_blocks = m_loaded_blocks;
  760. return ret;
  761. }
  762. void MMVManip::reparent(Map *map)
  763. {
  764. assert(map && !m_map);
  765. m_map = map;
  766. }
  767. //END