mapblock.cpp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. /*
  2. Minetest
  3. Copyright (C) 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 "mapblock.h"
  17. #include <sstream>
  18. #include "map.h"
  19. #include "light.h"
  20. #include "nodedef.h"
  21. #include "nodemetadata.h"
  22. #include "gamedef.h"
  23. #include "log.h"
  24. #include "nameidmapping.h"
  25. #include "content_mapnode.h" // For legacy name-id mapping
  26. #include "content_nodemeta.h" // For legacy deserialization
  27. #include "serialization.h"
  28. #ifndef SERVER
  29. #include "mapblock_mesh.h"
  30. #endif
  31. #include "util/string.h"
  32. #include "util/serialize.h"
  33. #include "util/basic_macros.h"
  34. static const char *modified_reason_strings[] = {
  35. "initial",
  36. "reallocate",
  37. "setIsUnderground",
  38. "setLightingExpired",
  39. "setGenerated",
  40. "setNode",
  41. "setNodeNoCheck",
  42. "setTimestamp",
  43. "NodeMetaRef::reportMetadataChange",
  44. "clearAllObjects",
  45. "Timestamp expired (step)",
  46. "addActiveObjectRaw",
  47. "removeRemovedObjects/remove",
  48. "removeRemovedObjects/deactivate",
  49. "Stored list cleared in activateObjects due to overflow",
  50. "deactivateFarObjects: Static data moved in",
  51. "deactivateFarObjects: Static data moved out",
  52. "deactivateFarObjects: Static data changed considerably",
  53. "finishBlockMake: expireDayNightDiff",
  54. "unknown",
  55. };
  56. /*
  57. MapBlock
  58. */
  59. MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
  60. m_parent(parent),
  61. m_pos(pos),
  62. m_pos_relative(pos * MAP_BLOCKSIZE),
  63. m_gamedef(gamedef)
  64. {
  65. if (!dummy)
  66. reallocate();
  67. }
  68. MapBlock::~MapBlock()
  69. {
  70. #ifndef SERVER
  71. {
  72. delete mesh;
  73. mesh = nullptr;
  74. }
  75. #endif
  76. delete[] data;
  77. }
  78. bool MapBlock::isValidPositionParent(v3s16 p)
  79. {
  80. if (isValidPosition(p)) {
  81. return true;
  82. }
  83. return m_parent->isValidPosition(getPosRelative() + p);
  84. }
  85. MapNode MapBlock::getNodeParent(v3s16 p, bool *is_valid_position)
  86. {
  87. if (!isValidPosition(p))
  88. return m_parent->getNodeNoEx(getPosRelative() + p, is_valid_position);
  89. if (!data) {
  90. if (is_valid_position)
  91. *is_valid_position = false;
  92. return {CONTENT_IGNORE};
  93. }
  94. if (is_valid_position)
  95. *is_valid_position = true;
  96. return data[p.Z * zstride + p.Y * ystride + p.X];
  97. }
  98. std::string MapBlock::getModifiedReasonString()
  99. {
  100. std::string reason;
  101. const u32 ubound = MYMIN(sizeof(m_modified_reason) * CHAR_BIT,
  102. ARRLEN(modified_reason_strings));
  103. for (u32 i = 0; i != ubound; i++) {
  104. if ((m_modified_reason & (1 << i)) == 0)
  105. continue;
  106. reason += modified_reason_strings[i];
  107. reason += ", ";
  108. }
  109. if (reason.length() > 2)
  110. reason.resize(reason.length() - 2);
  111. return reason;
  112. }
  113. /*
  114. Propagates sunlight down through the block.
  115. Doesn't modify nodes that are not affected by sunlight.
  116. Returns false if sunlight at bottom block is invalid.
  117. Returns true if sunlight at bottom block is valid.
  118. Returns true if bottom block doesn't exist.
  119. If there is a block above, continues from it.
  120. If there is no block above, assumes there is sunlight, unless
  121. is_underground is set or highest node is water.
  122. All sunlighted nodes are added to light_sources.
  123. if remove_light==true, sets non-sunlighted nodes black.
  124. if black_air_left!=NULL, it is set to true if non-sunlighted
  125. air is left in block.
  126. */
  127. bool MapBlock::propagateSunlight(std::set<v3s16> & light_sources,
  128. bool remove_light, bool *black_air_left)
  129. {
  130. INodeDefManager *nodemgr = m_gamedef->ndef();
  131. // Whether the sunlight at the top of the bottom block is valid
  132. bool block_below_is_valid = true;
  133. v3s16 pos_relative = getPosRelative();
  134. for(s16 x=0; x<MAP_BLOCKSIZE; x++)
  135. {
  136. for(s16 z=0; z<MAP_BLOCKSIZE; z++)
  137. {
  138. #if 1
  139. bool no_sunlight = false;
  140. //bool no_top_block = false;
  141. // Check if node above block has sunlight
  142. bool is_valid_position;
  143. MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z),
  144. &is_valid_position);
  145. if (is_valid_position)
  146. {
  147. if(n.getContent() == CONTENT_IGNORE)
  148. {
  149. // Trust heuristics
  150. no_sunlight = is_underground;
  151. }
  152. else if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN)
  153. {
  154. no_sunlight = true;
  155. }
  156. }
  157. else
  158. {
  159. //no_top_block = true;
  160. // NOTE: This makes over-ground roofed places sunlighted
  161. // Assume sunlight, unless is_underground==true
  162. if(is_underground)
  163. {
  164. no_sunlight = true;
  165. }
  166. else
  167. {
  168. MapNode n = getNodeNoEx(v3s16(x, MAP_BLOCKSIZE-1, z));
  169. if (!m_gamedef->ndef()->get(n).sunlight_propagates) {
  170. no_sunlight = true;
  171. }
  172. }
  173. // NOTE: As of now, this just would make everything dark.
  174. // No sunlight here
  175. //no_sunlight = true;
  176. }
  177. #endif
  178. #if 0 // Doesn't work; nothing gets light.
  179. bool no_sunlight = true;
  180. bool no_top_block = false;
  181. // Check if node above block has sunlight
  182. try{
  183. MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
  184. if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
  185. {
  186. no_sunlight = false;
  187. }
  188. }
  189. catch(InvalidPositionException &e)
  190. {
  191. no_top_block = true;
  192. }
  193. #endif
  194. /*std::cout<<"("<<x<<","<<z<<"): "
  195. <<"no_top_block="<<no_top_block
  196. <<", is_underground="<<is_underground
  197. <<", no_sunlight="<<no_sunlight
  198. <<std::endl;*/
  199. s16 y = MAP_BLOCKSIZE-1;
  200. // This makes difference to diminishing in water.
  201. bool stopped_to_solid_object = false;
  202. u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
  203. for(; y >= 0; y--)
  204. {
  205. v3s16 pos(x, y, z);
  206. MapNode &n = getNodeRef(pos);
  207. if(current_light == 0)
  208. {
  209. // Do nothing
  210. }
  211. else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates)
  212. {
  213. // Do nothing: Sunlight is continued
  214. } else if (!nodemgr->get(n).light_propagates) {
  215. // A solid object is on the way.
  216. stopped_to_solid_object = true;
  217. // Light stops.
  218. current_light = 0;
  219. }
  220. else
  221. {
  222. // Diminish light
  223. current_light = diminish_light(current_light);
  224. }
  225. u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr);
  226. if(current_light > old_light || remove_light)
  227. {
  228. n.setLight(LIGHTBANK_DAY, current_light, nodemgr);
  229. }
  230. if(diminish_light(current_light) != 0)
  231. {
  232. light_sources.insert(pos_relative + pos);
  233. }
  234. if(current_light == 0 && stopped_to_solid_object)
  235. {
  236. if(black_air_left)
  237. {
  238. *black_air_left = true;
  239. }
  240. }
  241. }
  242. // Whether or not the block below should see LIGHT_SUN
  243. bool sunlight_should_go_down = (current_light == LIGHT_SUN);
  244. /*
  245. If the block below hasn't already been marked invalid:
  246. Check if the node below the block has proper sunlight at top.
  247. If not, the block below is invalid.
  248. Ignore non-transparent nodes as they always have no light
  249. */
  250. if(block_below_is_valid)
  251. {
  252. MapNode n = getNodeParent(v3s16(x, -1, z), &is_valid_position);
  253. if (is_valid_position) {
  254. if(nodemgr->get(n).light_propagates)
  255. {
  256. if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN
  257. && !sunlight_should_go_down)
  258. block_below_is_valid = false;
  259. else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN
  260. && sunlight_should_go_down)
  261. block_below_is_valid = false;
  262. }
  263. }
  264. else
  265. {
  266. /*std::cout<<"InvalidBlockException for bottom block node"
  267. <<std::endl;*/
  268. // Just no block below, no need to panic.
  269. }
  270. }
  271. }
  272. }
  273. return block_below_is_valid;
  274. }
  275. void MapBlock::copyTo(VoxelManipulator &dst)
  276. {
  277. v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
  278. VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
  279. // Copy from data to VoxelManipulator
  280. dst.copyFrom(data, data_area, v3s16(0,0,0),
  281. getPosRelative(), data_size);
  282. }
  283. void MapBlock::copyFrom(VoxelManipulator &dst)
  284. {
  285. v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
  286. VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
  287. // Copy from VoxelManipulator to data
  288. dst.copyTo(data, data_area, v3s16(0,0,0),
  289. getPosRelative(), data_size);
  290. }
  291. void MapBlock::actuallyUpdateDayNightDiff()
  292. {
  293. INodeDefManager *nodemgr = m_gamedef->ndef();
  294. // Running this function un-expires m_day_night_differs
  295. m_day_night_differs_expired = false;
  296. if (!data) {
  297. m_day_night_differs = false;
  298. return;
  299. }
  300. bool differs = false;
  301. /*
  302. Check if any lighting value differs
  303. */
  304. MapNode previous_n(CONTENT_IGNORE);
  305. for (u32 i = 0; i < nodecount; i++) {
  306. MapNode n = data[i];
  307. // If node is identical to previous node, don't verify if it differs
  308. if (n == previous_n)
  309. continue;
  310. differs = !n.isLightDayNightEq(nodemgr);
  311. if (differs)
  312. break;
  313. previous_n = n;
  314. }
  315. /*
  316. If some lighting values differ, check if the whole thing is
  317. just air. If it is just air, differs = false
  318. */
  319. if (differs) {
  320. bool only_air = true;
  321. for (u32 i = 0; i < nodecount; i++) {
  322. MapNode &n = data[i];
  323. if (n.getContent() != CONTENT_AIR) {
  324. only_air = false;
  325. break;
  326. }
  327. }
  328. if (only_air)
  329. differs = false;
  330. }
  331. // Set member variable
  332. m_day_night_differs = differs;
  333. }
  334. void MapBlock::expireDayNightDiff()
  335. {
  336. if (!data) {
  337. m_day_night_differs = false;
  338. m_day_night_differs_expired = false;
  339. return;
  340. }
  341. m_day_night_differs_expired = true;
  342. }
  343. s16 MapBlock::getGroundLevel(v2s16 p2d)
  344. {
  345. if(isDummy())
  346. return -3;
  347. try
  348. {
  349. s16 y = MAP_BLOCKSIZE-1;
  350. for(; y>=0; y--)
  351. {
  352. MapNode n = getNodeRef(p2d.X, y, p2d.Y);
  353. if (m_gamedef->ndef()->get(n).walkable) {
  354. if(y == MAP_BLOCKSIZE-1)
  355. return -2;
  356. return y;
  357. }
  358. }
  359. return -1;
  360. }
  361. catch(InvalidPositionException &e)
  362. {
  363. return -3;
  364. }
  365. }
  366. /*
  367. Serialization
  368. */
  369. // List relevant id-name pairs for ids in the block using nodedef
  370. // Renumbers the content IDs (starting at 0 and incrementing
  371. // use static memory requires about 65535 * sizeof(int) ram in order to be
  372. // sure we can handle all content ids. But it's absolutely worth it as it's
  373. // a speedup of 4 for one of the major time consuming functions on storing
  374. // mapblocks.
  375. static content_t getBlockNodeIdMapping_mapping[USHRT_MAX + 1];
  376. static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
  377. INodeDefManager *nodedef)
  378. {
  379. memset(getBlockNodeIdMapping_mapping, 0xFF, (USHRT_MAX + 1) * sizeof(content_t));
  380. std::set<content_t> unknown_contents;
  381. content_t id_counter = 0;
  382. for (u32 i = 0; i < MapBlock::nodecount; i++) {
  383. content_t global_id = nodes[i].getContent();
  384. content_t id = CONTENT_IGNORE;
  385. // Try to find an existing mapping
  386. if (getBlockNodeIdMapping_mapping[global_id] != 0xFFFF) {
  387. id = getBlockNodeIdMapping_mapping[global_id];
  388. }
  389. else
  390. {
  391. // We have to assign a new mapping
  392. id = id_counter++;
  393. getBlockNodeIdMapping_mapping[global_id] = id;
  394. const ContentFeatures &f = nodedef->get(global_id);
  395. const std::string &name = f.name;
  396. if (name.empty())
  397. unknown_contents.insert(global_id);
  398. else
  399. nimap->set(id, name);
  400. }
  401. // Update the MapNode
  402. nodes[i].setContent(id);
  403. }
  404. for (u16 unknown_content : unknown_contents) {
  405. errorstream << "getBlockNodeIdMapping(): IGNORING ERROR: "
  406. << "Name for node id " << unknown_content << " not known" << std::endl;
  407. }
  408. }
  409. // Correct ids in the block to match nodedef based on names.
  410. // Unknown ones are added to nodedef.
  411. // Will not update itself to match id-name pairs in nodedef.
  412. static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
  413. IGameDef *gamedef)
  414. {
  415. INodeDefManager *nodedef = gamedef->ndef();
  416. // This means the block contains incorrect ids, and we contain
  417. // the information to convert those to names.
  418. // nodedef contains information to convert our names to globally
  419. // correct ids.
  420. std::unordered_set<content_t> unnamed_contents;
  421. std::unordered_set<std::string> unallocatable_contents;
  422. bool previous_exists = false;
  423. content_t previous_local_id = CONTENT_IGNORE;
  424. content_t previous_global_id = CONTENT_IGNORE;
  425. for (u32 i = 0; i < MapBlock::nodecount; i++) {
  426. content_t local_id = nodes[i].getContent();
  427. // If previous node local_id was found and same than before, don't lookup maps
  428. // apply directly previous resolved id
  429. // This permits to massively improve loading performance when nodes are similar
  430. // example: default:air, default:stone are massively present
  431. if (previous_exists && local_id == previous_local_id) {
  432. nodes[i].setContent(previous_global_id);
  433. continue;
  434. }
  435. std::string name;
  436. if (!nimap->getName(local_id, name)) {
  437. unnamed_contents.insert(local_id);
  438. previous_exists = false;
  439. continue;
  440. }
  441. content_t global_id;
  442. if (!nodedef->getId(name, global_id)) {
  443. global_id = gamedef->allocateUnknownNodeId(name);
  444. if (global_id == CONTENT_IGNORE) {
  445. unallocatable_contents.insert(name);
  446. previous_exists = false;
  447. continue;
  448. }
  449. }
  450. nodes[i].setContent(global_id);
  451. // Save previous node local_id & global_id result
  452. previous_local_id = local_id;
  453. previous_global_id = global_id;
  454. previous_exists = true;
  455. }
  456. for (const content_t c: unnamed_contents) {
  457. errorstream << "correctBlockNodeIds(): IGNORING ERROR: "
  458. << "Block contains id " << c
  459. << " with no name mapping" << std::endl;
  460. }
  461. for (const std::string &node_name: unallocatable_contents) {
  462. errorstream << "correctBlockNodeIds(): IGNORING ERROR: "
  463. << "Could not allocate global id for node name \""
  464. << node_name << "\"" << std::endl;
  465. }
  466. }
  467. void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
  468. {
  469. if(!ser_ver_supported(version))
  470. throw VersionMismatchException("ERROR: MapBlock format not supported");
  471. if (!data)
  472. throw SerializationError("ERROR: Not writing dummy block.");
  473. FATAL_ERROR_IF(version < SER_FMT_VER_LOWEST_WRITE, "Serialisation version error");
  474. // First byte
  475. u8 flags = 0;
  476. if(is_underground)
  477. flags |= 0x01;
  478. if(getDayNightDiff())
  479. flags |= 0x02;
  480. if (!m_generated)
  481. flags |= 0x08;
  482. writeU8(os, flags);
  483. if (version >= 27) {
  484. writeU16(os, m_lighting_complete);
  485. }
  486. /*
  487. Bulk node data
  488. */
  489. NameIdMapping nimap;
  490. if(disk)
  491. {
  492. MapNode *tmp_nodes = new MapNode[nodecount];
  493. for(u32 i=0; i<nodecount; i++)
  494. tmp_nodes[i] = data[i];
  495. getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
  496. u8 content_width = 2;
  497. u8 params_width = 2;
  498. writeU8(os, content_width);
  499. writeU8(os, params_width);
  500. MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
  501. content_width, params_width, true);
  502. delete[] tmp_nodes;
  503. }
  504. else
  505. {
  506. u8 content_width = 2;
  507. u8 params_width = 2;
  508. writeU8(os, content_width);
  509. writeU8(os, params_width);
  510. MapNode::serializeBulk(os, version, data, nodecount,
  511. content_width, params_width, true);
  512. }
  513. /*
  514. Node metadata
  515. */
  516. std::ostringstream oss(std::ios_base::binary);
  517. m_node_metadata.serialize(oss, version, disk);
  518. compressZlib(oss.str(), os);
  519. /*
  520. Data that goes to disk, but not the network
  521. */
  522. if(disk)
  523. {
  524. if(version <= 24){
  525. // Node timers
  526. m_node_timers.serialize(os, version);
  527. }
  528. // Static objects
  529. m_static_objects.serialize(os);
  530. // Timestamp
  531. writeU32(os, getTimestamp());
  532. // Write block-specific node definition id mapping
  533. nimap.serialize(os);
  534. if(version >= 25){
  535. // Node timers
  536. m_node_timers.serialize(os, version);
  537. }
  538. }
  539. }
  540. void MapBlock::serializeNetworkSpecific(std::ostream &os)
  541. {
  542. if (!data) {
  543. throw SerializationError("ERROR: Not writing dummy block.");
  544. }
  545. writeU8(os, 1); // version
  546. writeF1000(os, 0); // deprecated heat
  547. writeF1000(os, 0); // deprecated humidity
  548. }
  549. void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
  550. {
  551. if(!ser_ver_supported(version))
  552. throw VersionMismatchException("ERROR: MapBlock format not supported");
  553. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())<<std::endl);
  554. m_day_night_differs_expired = false;
  555. if(version <= 21)
  556. {
  557. deSerialize_pre22(is, version, disk);
  558. return;
  559. }
  560. u8 flags = readU8(is);
  561. is_underground = (flags & 0x01) != 0;
  562. m_day_night_differs = (flags & 0x02) != 0;
  563. if (version < 27)
  564. m_lighting_complete = 0xFFFF;
  565. else
  566. m_lighting_complete = readU16(is);
  567. m_generated = (flags & 0x08) == 0;
  568. /*
  569. Bulk node data
  570. */
  571. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  572. <<": Bulk node data"<<std::endl);
  573. u8 content_width = readU8(is);
  574. u8 params_width = readU8(is);
  575. if(content_width != 1 && content_width != 2)
  576. throw SerializationError("MapBlock::deSerialize(): invalid content_width");
  577. if(params_width != 2)
  578. throw SerializationError("MapBlock::deSerialize(): invalid params_width");
  579. MapNode::deSerializeBulk(is, version, data, nodecount,
  580. content_width, params_width, true);
  581. /*
  582. NodeMetadata
  583. */
  584. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  585. <<": Node metadata"<<std::endl);
  586. // Ignore errors
  587. try {
  588. std::ostringstream oss(std::ios_base::binary);
  589. decompressZlib(is, oss);
  590. std::istringstream iss(oss.str(), std::ios_base::binary);
  591. if (version >= 23)
  592. m_node_metadata.deSerialize(iss, m_gamedef->idef());
  593. else
  594. content_nodemeta_deserialize_legacy(iss,
  595. &m_node_metadata, &m_node_timers,
  596. m_gamedef->idef());
  597. } catch(SerializationError &e) {
  598. warningstream<<"MapBlock::deSerialize(): Ignoring an error"
  599. <<" while deserializing node metadata at ("
  600. <<PP(getPos())<<": "<<e.what()<<std::endl;
  601. }
  602. /*
  603. Data that is only on disk
  604. */
  605. if(disk)
  606. {
  607. // Node timers
  608. if(version == 23){
  609. // Read unused zero
  610. readU8(is);
  611. }
  612. if(version == 24){
  613. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  614. <<": Node timers (ver==24)"<<std::endl);
  615. m_node_timers.deSerialize(is, version);
  616. }
  617. // Static objects
  618. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  619. <<": Static objects"<<std::endl);
  620. m_static_objects.deSerialize(is);
  621. // Timestamp
  622. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  623. <<": Timestamp"<<std::endl);
  624. setTimestamp(readU32(is));
  625. m_disk_timestamp = m_timestamp;
  626. // Dynamically re-set ids based on node names
  627. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  628. <<": NameIdMapping"<<std::endl);
  629. NameIdMapping nimap;
  630. nimap.deSerialize(is);
  631. correctBlockNodeIds(&nimap, data, m_gamedef);
  632. if(version >= 25){
  633. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  634. <<": Node timers (ver>=25)"<<std::endl);
  635. m_node_timers.deSerialize(is, version);
  636. }
  637. }
  638. TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
  639. <<": Done."<<std::endl);
  640. }
  641. void MapBlock::deSerializeNetworkSpecific(std::istream &is)
  642. {
  643. try {
  644. int version = readU8(is);
  645. //if(version != 1)
  646. // throw SerializationError("unsupported MapBlock version");
  647. if(version >= 1) {
  648. readF1000(is); // deprecated heat
  649. readF1000(is); // deprecated humidity
  650. }
  651. }
  652. catch(SerializationError &e)
  653. {
  654. warningstream<<"MapBlock::deSerializeNetworkSpecific(): Ignoring an error"
  655. <<": "<<e.what()<<std::endl;
  656. }
  657. }
  658. /*
  659. Legacy serialization
  660. */
  661. void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
  662. {
  663. // Initialize default flags
  664. is_underground = false;
  665. m_day_night_differs = false;
  666. m_lighting_complete = 0xFFFF;
  667. m_generated = true;
  668. // Make a temporary buffer
  669. u32 ser_length = MapNode::serializedLength(version);
  670. SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
  671. // These have no compression
  672. if (version <= 3 || version == 5 || version == 6) {
  673. char tmp;
  674. is.read(&tmp, 1);
  675. if (is.gcount() != 1)
  676. throw SerializationError(std::string(FUNCTION_NAME)
  677. + ": not enough input data");
  678. is_underground = tmp;
  679. is.read((char *)*databuf_nodelist, nodecount * ser_length);
  680. if ((u32)is.gcount() != nodecount * ser_length)
  681. throw SerializationError(std::string(FUNCTION_NAME)
  682. + ": not enough input data");
  683. } else if (version <= 10) {
  684. u8 t8;
  685. is.read((char *)&t8, 1);
  686. is_underground = t8;
  687. {
  688. // Uncompress and set material data
  689. std::ostringstream os(std::ios_base::binary);
  690. decompress(is, os, version);
  691. std::string s = os.str();
  692. if (s.size() != nodecount)
  693. throw SerializationError(std::string(FUNCTION_NAME)
  694. + ": not enough input data");
  695. for (u32 i = 0; i < s.size(); i++) {
  696. databuf_nodelist[i*ser_length] = s[i];
  697. }
  698. }
  699. {
  700. // Uncompress and set param data
  701. std::ostringstream os(std::ios_base::binary);
  702. decompress(is, os, version);
  703. std::string s = os.str();
  704. if (s.size() != nodecount)
  705. throw SerializationError(std::string(FUNCTION_NAME)
  706. + ": not enough input data");
  707. for (u32 i = 0; i < s.size(); i++) {
  708. databuf_nodelist[i*ser_length + 1] = s[i];
  709. }
  710. }
  711. if (version >= 10) {
  712. // Uncompress and set param2 data
  713. std::ostringstream os(std::ios_base::binary);
  714. decompress(is, os, version);
  715. std::string s = os.str();
  716. if (s.size() != nodecount)
  717. throw SerializationError(std::string(FUNCTION_NAME)
  718. + ": not enough input data");
  719. for (u32 i = 0; i < s.size(); i++) {
  720. databuf_nodelist[i*ser_length + 2] = s[i];
  721. }
  722. }
  723. } else { // All other versions (10 to 21)
  724. u8 flags;
  725. is.read((char*)&flags, 1);
  726. is_underground = (flags & 0x01) != 0;
  727. m_day_night_differs = (flags & 0x02) != 0;
  728. if(version >= 18)
  729. m_generated = (flags & 0x08) == 0;
  730. // Uncompress data
  731. std::ostringstream os(std::ios_base::binary);
  732. decompress(is, os, version);
  733. std::string s = os.str();
  734. if (s.size() != nodecount * 3)
  735. throw SerializationError(std::string(FUNCTION_NAME)
  736. + ": decompress resulted in size other than nodecount*3");
  737. // deserialize nodes from buffer
  738. for (u32 i = 0; i < nodecount; i++) {
  739. databuf_nodelist[i*ser_length] = s[i];
  740. databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
  741. databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
  742. }
  743. /*
  744. NodeMetadata
  745. */
  746. if (version >= 14) {
  747. // Ignore errors
  748. try {
  749. if (version <= 15) {
  750. std::string data = deSerializeString(is);
  751. std::istringstream iss(data, std::ios_base::binary);
  752. content_nodemeta_deserialize_legacy(iss,
  753. &m_node_metadata, &m_node_timers,
  754. m_gamedef->idef());
  755. } else {
  756. //std::string data = deSerializeLongString(is);
  757. std::ostringstream oss(std::ios_base::binary);
  758. decompressZlib(is, oss);
  759. std::istringstream iss(oss.str(), std::ios_base::binary);
  760. content_nodemeta_deserialize_legacy(iss,
  761. &m_node_metadata, &m_node_timers,
  762. m_gamedef->idef());
  763. }
  764. } catch(SerializationError &e) {
  765. warningstream<<"MapBlock::deSerialize(): Ignoring an error"
  766. <<" while deserializing node metadata"<<std::endl;
  767. }
  768. }
  769. }
  770. // Deserialize node data
  771. for (u32 i = 0; i < nodecount; i++) {
  772. data[i].deSerialize(&databuf_nodelist[i * ser_length], version);
  773. }
  774. if (disk) {
  775. /*
  776. Versions up from 9 have block objects. (DEPRECATED)
  777. */
  778. if (version >= 9) {
  779. u16 count = readU16(is);
  780. // Not supported and length not known if count is not 0
  781. if(count != 0){
  782. warningstream<<"MapBlock::deSerialize_pre22(): "
  783. <<"Ignoring stuff coming at and after MBOs"<<std::endl;
  784. return;
  785. }
  786. }
  787. /*
  788. Versions up from 15 have static objects.
  789. */
  790. if (version >= 15)
  791. m_static_objects.deSerialize(is);
  792. // Timestamp
  793. if (version >= 17) {
  794. setTimestamp(readU32(is));
  795. m_disk_timestamp = m_timestamp;
  796. } else {
  797. setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
  798. }
  799. // Dynamically re-set ids based on node names
  800. NameIdMapping nimap;
  801. // If supported, read node definition id mapping
  802. if (version >= 21) {
  803. nimap.deSerialize(is);
  804. // Else set the legacy mapping
  805. } else {
  806. content_mapnode_get_name_id_mapping(&nimap);
  807. }
  808. correctBlockNodeIds(&nimap, data, m_gamedef);
  809. }
  810. // Legacy data changes
  811. // This code has to convert from pre-22 to post-22 format.
  812. INodeDefManager *nodedef = m_gamedef->ndef();
  813. for(u32 i=0; i<nodecount; i++)
  814. {
  815. const ContentFeatures &f = nodedef->get(data[i].getContent());
  816. // Mineral
  817. if(nodedef->getId("default:stone") == data[i].getContent()
  818. && data[i].getParam1() == 1)
  819. {
  820. data[i].setContent(nodedef->getId("default:stone_with_coal"));
  821. data[i].setParam1(0);
  822. }
  823. else if(nodedef->getId("default:stone") == data[i].getContent()
  824. && data[i].getParam1() == 2)
  825. {
  826. data[i].setContent(nodedef->getId("default:stone_with_iron"));
  827. data[i].setParam1(0);
  828. }
  829. // facedir_simple
  830. if(f.legacy_facedir_simple)
  831. {
  832. data[i].setParam2(data[i].getParam1());
  833. data[i].setParam1(0);
  834. }
  835. // wall_mounted
  836. if(f.legacy_wallmounted)
  837. {
  838. u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
  839. u8 dir_old_format = data[i].getParam2();
  840. u8 dir_new_format = 0;
  841. for(u8 j=0; j<8; j++)
  842. {
  843. if((dir_old_format & wallmounted_new_to_old[j]) != 0)
  844. {
  845. dir_new_format = j;
  846. break;
  847. }
  848. }
  849. data[i].setParam2(dir_new_format);
  850. }
  851. }
  852. }
  853. /*
  854. Get a quick string to describe what a block actually contains
  855. */
  856. std::string analyze_block(MapBlock *block)
  857. {
  858. if(block == NULL)
  859. return "NULL";
  860. std::ostringstream desc;
  861. v3s16 p = block->getPos();
  862. char spos[25];
  863. snprintf(spos, sizeof(spos), "(%2d,%2d,%2d), ", p.X, p.Y, p.Z);
  864. desc<<spos;
  865. switch(block->getModified())
  866. {
  867. case MOD_STATE_CLEAN:
  868. desc<<"CLEAN, ";
  869. break;
  870. case MOD_STATE_WRITE_AT_UNLOAD:
  871. desc<<"WRITE_AT_UNLOAD, ";
  872. break;
  873. case MOD_STATE_WRITE_NEEDED:
  874. desc<<"WRITE_NEEDED, ";
  875. break;
  876. default:
  877. desc<<"unknown getModified()="+itos(block->getModified())+", ";
  878. }
  879. if(block->isGenerated())
  880. desc<<"is_gen [X], ";
  881. else
  882. desc<<"is_gen [ ], ";
  883. if(block->getIsUnderground())
  884. desc<<"is_ug [X], ";
  885. else
  886. desc<<"is_ug [ ], ";
  887. desc<<"lighting_complete: "<<block->getLightingComplete()<<", ";
  888. if(block->isDummy())
  889. {
  890. desc<<"Dummy, ";
  891. }
  892. else
  893. {
  894. bool full_ignore = true;
  895. bool some_ignore = false;
  896. bool full_air = true;
  897. bool some_air = false;
  898. for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
  899. for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
  900. for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
  901. {
  902. v3s16 p(x0,y0,z0);
  903. MapNode n = block->getNodeNoEx(p);
  904. content_t c = n.getContent();
  905. if(c == CONTENT_IGNORE)
  906. some_ignore = true;
  907. else
  908. full_ignore = false;
  909. if(c == CONTENT_AIR)
  910. some_air = true;
  911. else
  912. full_air = false;
  913. }
  914. desc<<"content {";
  915. std::ostringstream ss;
  916. if(full_ignore)
  917. ss<<"IGNORE (full), ";
  918. else if(some_ignore)
  919. ss<<"IGNORE, ";
  920. if(full_air)
  921. ss<<"AIR (full), ";
  922. else if(some_air)
  923. ss<<"AIR, ";
  924. if(ss.str().size()>=2)
  925. desc<<ss.str().substr(0, ss.str().size()-2);
  926. desc<<"}, ";
  927. }
  928. return desc.str().substr(0, desc.str().size()-2);
  929. }
  930. //END