mapnode.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  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 "irrlichttypes_extrabloated.h"
  17. #include "mapnode.h"
  18. #include "porting.h"
  19. #include "nodedef.h"
  20. #include "map.h"
  21. #include "content_mapnode.h" // For mapnode_translate_*_internal
  22. #include "serialization.h" // For ser_ver_supported
  23. #include "util/serialize.h"
  24. #include "log.h"
  25. #include "util/directiontables.h"
  26. #include "util/numeric.h"
  27. #include <string>
  28. #include <sstream>
  29. static const Rotation wallmounted_to_rot[] = {
  30. ROTATE_0, ROTATE_180, ROTATE_90, ROTATE_270
  31. };
  32. static const u8 rot_to_wallmounted[] = {
  33. 2, 4, 3, 5
  34. };
  35. /*
  36. MapNode
  37. */
  38. void MapNode::getColor(const ContentFeatures &f, video::SColor *color) const
  39. {
  40. if (f.palette) {
  41. *color = (*f.palette)[param2];
  42. return;
  43. }
  44. *color = f.color;
  45. }
  46. u8 MapNode::getFaceDir(const NodeDefManager *nodemgr,
  47. bool allow_wallmounted) const
  48. {
  49. const ContentFeatures &f = nodemgr->get(*this);
  50. if (f.param_type_2 == CPT2_FACEDIR ||
  51. f.param_type_2 == CPT2_COLORED_FACEDIR)
  52. return (getParam2() & 0x1F) % 24;
  53. if (f.param_type_2 == CPT2_4DIR ||
  54. f.param_type_2 == CPT2_COLORED_4DIR)
  55. return getParam2() & 0x03;
  56. if (allow_wallmounted && (f.param_type_2 == CPT2_WALLMOUNTED ||
  57. f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
  58. u8 wmountface = MYMIN(getParam2() & 0x07, DWM_COUNT - 1);
  59. return wallmounted_to_facedir[wmountface];
  60. }
  61. return 0;
  62. }
  63. u8 MapNode::getWallMounted(const NodeDefManager *nodemgr) const
  64. {
  65. const ContentFeatures &f = nodemgr->get(*this);
  66. if (f.param_type_2 == CPT2_WALLMOUNTED ||
  67. f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
  68. return MYMIN(getParam2() & 0x07, DWM_COUNT - 1);
  69. else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE ||
  70. f.drawtype == NDT_PLANTLIKE ||
  71. f.drawtype == NDT_PLANTLIKE_ROOTED) {
  72. return 1;
  73. }
  74. return 0;
  75. }
  76. v3s16 MapNode::getWallMountedDir(const NodeDefManager *nodemgr) const
  77. {
  78. switch(getWallMounted(nodemgr))
  79. {
  80. case 0: default: return v3s16(0,1,0);
  81. case 1: return v3s16(0,-1,0);
  82. case 2: return v3s16(1,0,0);
  83. case 3: return v3s16(-1,0,0);
  84. case 4: return v3s16(0,0,1);
  85. case 5: return v3s16(0,0,-1);
  86. case 6: return v3s16(0,1,0);
  87. case 7: return v3s16(0,-1,0);
  88. }
  89. }
  90. u8 MapNode::getDegRotate(const NodeDefManager *nodemgr) const
  91. {
  92. const ContentFeatures &f = nodemgr->get(*this);
  93. if (f.param_type_2 == CPT2_DEGROTATE)
  94. return getParam2() % 240;
  95. if (f.param_type_2 == CPT2_COLORED_DEGROTATE)
  96. return 10 * ((getParam2() & 0x1F) % 24);
  97. return 0;
  98. }
  99. void MapNode::rotateAlongYAxis(const NodeDefManager *nodemgr, Rotation rot)
  100. {
  101. ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2;
  102. if (cpt2 == CPT2_FACEDIR || cpt2 == CPT2_COLORED_FACEDIR ||
  103. cpt2 == CPT2_4DIR || cpt2 == CPT2_COLORED_4DIR) {
  104. static const u8 rotate_facedir[24 * 4] = {
  105. // Table value = rotated facedir
  106. // Columns: 0, 90, 180, 270 degrees rotation around vertical axis
  107. // Rotation is anticlockwise as seen from above (+Y)
  108. 0, 1, 2, 3, // Initial facedir 0 to 3
  109. 1, 2, 3, 0,
  110. 2, 3, 0, 1,
  111. 3, 0, 1, 2,
  112. 4, 13, 10, 19, // 4 to 7
  113. 5, 14, 11, 16,
  114. 6, 15, 8, 17,
  115. 7, 12, 9, 18,
  116. 8, 17, 6, 15, // 8 to 11
  117. 9, 18, 7, 12,
  118. 10, 19, 4, 13,
  119. 11, 16, 5, 14,
  120. 12, 9, 18, 7, // 12 to 15
  121. 13, 10, 19, 4,
  122. 14, 11, 16, 5,
  123. 15, 8, 17, 6,
  124. 16, 5, 14, 11, // 16 to 19
  125. 17, 6, 15, 8,
  126. 18, 7, 12, 9,
  127. 19, 4, 13, 10,
  128. 20, 23, 22, 21, // 20 to 23
  129. 21, 20, 23, 22,
  130. 22, 21, 20, 23,
  131. 23, 22, 21, 20
  132. };
  133. if (cpt2 == CPT2_FACEDIR || cpt2 == CPT2_COLORED_FACEDIR) {
  134. u8 facedir = (param2 & 31) % 24;
  135. u8 index = facedir * 4 + rot;
  136. param2 &= ~31;
  137. param2 |= rotate_facedir[index];
  138. } else if (cpt2 == CPT2_4DIR || cpt2 == CPT2_COLORED_4DIR) {
  139. u8 fourdir = param2 & 3;
  140. u8 index = fourdir * 4 + rot;
  141. param2 &= ~3;
  142. param2 |= rotate_facedir[index];
  143. }
  144. } else if (cpt2 == CPT2_WALLMOUNTED ||
  145. cpt2 == CPT2_COLORED_WALLMOUNTED) {
  146. u8 wmountface = MYMIN(param2 & 0x07, DWM_COUNT - 1);
  147. if (wmountface <= 1)
  148. return;
  149. Rotation oldrot = wallmounted_to_rot[wmountface - 2];
  150. param2 &= ~7;
  151. param2 |= rot_to_wallmounted[(oldrot - rot) & 3];
  152. } else if (cpt2 == CPT2_DEGROTATE) {
  153. int angle = param2; // in 1.5°
  154. angle += 60 * rot; // don’t do that on u8
  155. angle %= 240;
  156. param2 = angle;
  157. } else if (cpt2 == CPT2_COLORED_DEGROTATE) {
  158. int angle = param2 & 0x1F; // in 15°
  159. int color = param2 & 0xE0;
  160. angle += 6 * rot;
  161. angle %= 24;
  162. param2 = color | angle;
  163. }
  164. }
  165. void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
  166. const NodeDefManager *nodemgr, std::vector<aabb3f> *p_boxes,
  167. u8 neighbors = 0)
  168. {
  169. std::vector<aabb3f> &boxes = *p_boxes;
  170. if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) {
  171. const auto &fixed = nodebox.fixed;
  172. int facedir = n.getFaceDir(nodemgr, true);
  173. u8 axisdir = facedir>>2;
  174. facedir&=0x03;
  175. boxes.reserve(boxes.size() + fixed.size());
  176. for (aabb3f box : fixed) {
  177. if (nodebox.type == NODEBOX_LEVELED)
  178. box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS;
  179. switch (axisdir) {
  180. case 0:
  181. if(facedir == 1)
  182. {
  183. box.MinEdge.rotateXZBy(-90);
  184. box.MaxEdge.rotateXZBy(-90);
  185. }
  186. else if(facedir == 2)
  187. {
  188. box.MinEdge.rotateXZBy(180);
  189. box.MaxEdge.rotateXZBy(180);
  190. }
  191. else if(facedir == 3)
  192. {
  193. box.MinEdge.rotateXZBy(90);
  194. box.MaxEdge.rotateXZBy(90);
  195. }
  196. break;
  197. case 1: // z+
  198. box.MinEdge.rotateYZBy(90);
  199. box.MaxEdge.rotateYZBy(90);
  200. if(facedir == 1)
  201. {
  202. box.MinEdge.rotateXYBy(90);
  203. box.MaxEdge.rotateXYBy(90);
  204. }
  205. else if(facedir == 2)
  206. {
  207. box.MinEdge.rotateXYBy(180);
  208. box.MaxEdge.rotateXYBy(180);
  209. }
  210. else if(facedir == 3)
  211. {
  212. box.MinEdge.rotateXYBy(-90);
  213. box.MaxEdge.rotateXYBy(-90);
  214. }
  215. break;
  216. case 2: //z-
  217. box.MinEdge.rotateYZBy(-90);
  218. box.MaxEdge.rotateYZBy(-90);
  219. if(facedir == 1)
  220. {
  221. box.MinEdge.rotateXYBy(-90);
  222. box.MaxEdge.rotateXYBy(-90);
  223. }
  224. else if(facedir == 2)
  225. {
  226. box.MinEdge.rotateXYBy(180);
  227. box.MaxEdge.rotateXYBy(180);
  228. }
  229. else if(facedir == 3)
  230. {
  231. box.MinEdge.rotateXYBy(90);
  232. box.MaxEdge.rotateXYBy(90);
  233. }
  234. break;
  235. case 3: //x+
  236. box.MinEdge.rotateXYBy(-90);
  237. box.MaxEdge.rotateXYBy(-90);
  238. if(facedir == 1)
  239. {
  240. box.MinEdge.rotateYZBy(90);
  241. box.MaxEdge.rotateYZBy(90);
  242. }
  243. else if(facedir == 2)
  244. {
  245. box.MinEdge.rotateYZBy(180);
  246. box.MaxEdge.rotateYZBy(180);
  247. }
  248. else if(facedir == 3)
  249. {
  250. box.MinEdge.rotateYZBy(-90);
  251. box.MaxEdge.rotateYZBy(-90);
  252. }
  253. break;
  254. case 4: //x-
  255. box.MinEdge.rotateXYBy(90);
  256. box.MaxEdge.rotateXYBy(90);
  257. if(facedir == 1)
  258. {
  259. box.MinEdge.rotateYZBy(-90);
  260. box.MaxEdge.rotateYZBy(-90);
  261. }
  262. else if(facedir == 2)
  263. {
  264. box.MinEdge.rotateYZBy(180);
  265. box.MaxEdge.rotateYZBy(180);
  266. }
  267. else if(facedir == 3)
  268. {
  269. box.MinEdge.rotateYZBy(90);
  270. box.MaxEdge.rotateYZBy(90);
  271. }
  272. break;
  273. case 5:
  274. box.MinEdge.rotateXYBy(-180);
  275. box.MaxEdge.rotateXYBy(-180);
  276. if(facedir == 1)
  277. {
  278. box.MinEdge.rotateXZBy(90);
  279. box.MaxEdge.rotateXZBy(90);
  280. }
  281. else if(facedir == 2)
  282. {
  283. box.MinEdge.rotateXZBy(180);
  284. box.MaxEdge.rotateXZBy(180);
  285. }
  286. else if(facedir == 3)
  287. {
  288. box.MinEdge.rotateXZBy(-90);
  289. box.MaxEdge.rotateXZBy(-90);
  290. }
  291. break;
  292. default:
  293. break;
  294. }
  295. box.repair();
  296. boxes.push_back(box);
  297. }
  298. }
  299. else if(nodebox.type == NODEBOX_WALLMOUNTED)
  300. {
  301. v3s16 dir = n.getWallMountedDir(nodemgr);
  302. u8 wall = n.getWallMounted(nodemgr);
  303. // top
  304. if(dir == v3s16(0,1,0))
  305. {
  306. if (wall == DWM_S1) {
  307. v3f vertices[2] =
  308. {
  309. nodebox.wall_top.MinEdge,
  310. nodebox.wall_top.MaxEdge
  311. };
  312. for (v3f &vertex : vertices) {
  313. vertex.rotateXZBy(90);
  314. }
  315. aabb3f box = aabb3f(vertices[0]);
  316. box.addInternalPoint(vertices[1]);
  317. boxes.push_back(box);
  318. } else {
  319. boxes.push_back(nodebox.wall_top);
  320. }
  321. }
  322. // bottom
  323. else if(dir == v3s16(0,-1,0))
  324. {
  325. if (wall == DWM_S2) {
  326. v3f vertices[2] =
  327. {
  328. nodebox.wall_bottom.MinEdge,
  329. nodebox.wall_bottom.MaxEdge
  330. };
  331. for (v3f &vertex : vertices) {
  332. vertex.rotateXZBy(-90);
  333. }
  334. aabb3f box = aabb3f(vertices[0]);
  335. box.addInternalPoint(vertices[1]);
  336. boxes.push_back(box);
  337. } else {
  338. boxes.push_back(nodebox.wall_bottom);
  339. }
  340. }
  341. // side
  342. else
  343. {
  344. v3f vertices[2] =
  345. {
  346. nodebox.wall_side.MinEdge,
  347. nodebox.wall_side.MaxEdge
  348. };
  349. for (v3f &vertex : vertices) {
  350. if(dir == v3s16(-1,0,0))
  351. vertex.rotateXZBy(0);
  352. if(dir == v3s16(1,0,0))
  353. vertex.rotateXZBy(180);
  354. if(dir == v3s16(0,0,-1))
  355. vertex.rotateXZBy(90);
  356. if(dir == v3s16(0,0,1))
  357. vertex.rotateXZBy(-90);
  358. }
  359. aabb3f box = aabb3f(vertices[0]);
  360. box.addInternalPoint(vertices[1]);
  361. boxes.push_back(box);
  362. }
  363. }
  364. else if (nodebox.type == NODEBOX_CONNECTED)
  365. {
  366. size_t boxes_size = boxes.size();
  367. boxes_size += nodebox.fixed.size();
  368. const auto &c = nodebox.getConnected();
  369. if (neighbors & 1)
  370. boxes_size += c.connect_top.size();
  371. else
  372. boxes_size += c.disconnected_top.size();
  373. if (neighbors & 2)
  374. boxes_size += c.connect_bottom.size();
  375. else
  376. boxes_size += c.disconnected_bottom.size();
  377. if (neighbors & 4)
  378. boxes_size += c.connect_front.size();
  379. else
  380. boxes_size += c.disconnected_front.size();
  381. if (neighbors & 8)
  382. boxes_size += c.connect_left.size();
  383. else
  384. boxes_size += c.disconnected_left.size();
  385. if (neighbors & 16)
  386. boxes_size += c.connect_back.size();
  387. else
  388. boxes_size += c.disconnected_back.size();
  389. if (neighbors & 32)
  390. boxes_size += c.connect_right.size();
  391. else
  392. boxes_size += c.disconnected_right.size();
  393. if (neighbors == 0)
  394. boxes_size += c.disconnected.size();
  395. if (neighbors < 4)
  396. boxes_size += c.disconnected_sides.size();
  397. boxes.reserve(boxes_size);
  398. #define BOXESPUSHBACK(c) \
  399. for (std::vector<aabb3f>::const_iterator \
  400. it = (c).begin(); \
  401. it != (c).end(); ++it) \
  402. (boxes).push_back(*it);
  403. BOXESPUSHBACK(nodebox.fixed);
  404. if (neighbors & 1) {
  405. BOXESPUSHBACK(c.connect_top);
  406. } else {
  407. BOXESPUSHBACK(c.disconnected_top);
  408. }
  409. if (neighbors & 2) {
  410. BOXESPUSHBACK(c.connect_bottom);
  411. } else {
  412. BOXESPUSHBACK(c.disconnected_bottom);
  413. }
  414. if (neighbors & 4) {
  415. BOXESPUSHBACK(c.connect_front);
  416. } else {
  417. BOXESPUSHBACK(c.disconnected_front);
  418. }
  419. if (neighbors & 8) {
  420. BOXESPUSHBACK(c.connect_left);
  421. } else {
  422. BOXESPUSHBACK(c.disconnected_left);
  423. }
  424. if (neighbors & 16) {
  425. BOXESPUSHBACK(c.connect_back);
  426. } else {
  427. BOXESPUSHBACK(c.disconnected_back);
  428. }
  429. if (neighbors & 32) {
  430. BOXESPUSHBACK(c.connect_right);
  431. } else {
  432. BOXESPUSHBACK(c.disconnected_right);
  433. }
  434. if (neighbors == 0) {
  435. BOXESPUSHBACK(c.disconnected);
  436. }
  437. if (neighbors < 4) {
  438. BOXESPUSHBACK(c.disconnected_sides);
  439. }
  440. }
  441. else // NODEBOX_REGULAR
  442. {
  443. boxes.emplace_back(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
  444. }
  445. }
  446. static inline void getNeighborConnectingFace(
  447. const v3s16 &p, const NodeDefManager *nodedef,
  448. Map *map, MapNode n, u8 bitmask, u8 *neighbors)
  449. {
  450. MapNode n2 = map->getNode(p);
  451. if (nodedef->nodeboxConnects(n, n2, bitmask))
  452. *neighbors |= bitmask;
  453. }
  454. u8 MapNode::getNeighbors(v3s16 p, Map *map) const
  455. {
  456. const NodeDefManager *nodedef = map->getNodeDefManager();
  457. u8 neighbors = 0;
  458. const ContentFeatures &f = nodedef->get(*this);
  459. // locate possible neighboring nodes to connect to
  460. if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
  461. v3s16 p2 = p;
  462. p2.Y++;
  463. getNeighborConnectingFace(p2, nodedef, map, *this, 1, &neighbors);
  464. p2 = p;
  465. p2.Y--;
  466. getNeighborConnectingFace(p2, nodedef, map, *this, 2, &neighbors);
  467. p2 = p;
  468. p2.Z--;
  469. getNeighborConnectingFace(p2, nodedef, map, *this, 4, &neighbors);
  470. p2 = p;
  471. p2.X--;
  472. getNeighborConnectingFace(p2, nodedef, map, *this, 8, &neighbors);
  473. p2 = p;
  474. p2.Z++;
  475. getNeighborConnectingFace(p2, nodedef, map, *this, 16, &neighbors);
  476. p2 = p;
  477. p2.X++;
  478. getNeighborConnectingFace(p2, nodedef, map, *this, 32, &neighbors);
  479. }
  480. return neighbors;
  481. }
  482. void MapNode::getNodeBoxes(const NodeDefManager *nodemgr,
  483. std::vector<aabb3f> *boxes, u8 neighbors) const
  484. {
  485. const ContentFeatures &f = nodemgr->get(*this);
  486. transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
  487. }
  488. void MapNode::getCollisionBoxes(const NodeDefManager *nodemgr,
  489. std::vector<aabb3f> *boxes, u8 neighbors) const
  490. {
  491. const ContentFeatures &f = nodemgr->get(*this);
  492. if (f.collision_box.fixed.empty())
  493. transformNodeBox(*this, f.node_box, nodemgr, boxes, neighbors);
  494. else
  495. transformNodeBox(*this, f.collision_box, nodemgr, boxes, neighbors);
  496. }
  497. void MapNode::getSelectionBoxes(const NodeDefManager *nodemgr,
  498. std::vector<aabb3f> *boxes, u8 neighbors) const
  499. {
  500. const ContentFeatures &f = nodemgr->get(*this);
  501. transformNodeBox(*this, f.selection_box, nodemgr, boxes, neighbors);
  502. }
  503. u8 MapNode::getMaxLevel(const NodeDefManager *nodemgr) const
  504. {
  505. const ContentFeatures &f = nodemgr->get(*this);
  506. // todo: after update in all games leave only if (f.param_type_2 ==
  507. if( f.liquid_type == LIQUID_FLOWING || f.param_type_2 == CPT2_FLOWINGLIQUID)
  508. return LIQUID_LEVEL_MAX;
  509. if(f.leveled || f.param_type_2 == CPT2_LEVELED)
  510. return f.leveled_max;
  511. return 0;
  512. }
  513. u8 MapNode::getLevel(const NodeDefManager *nodemgr) const
  514. {
  515. const ContentFeatures &f = nodemgr->get(*this);
  516. // todo: after update in all games leave only if (f.param_type_2 ==
  517. if(f.liquid_type == LIQUID_SOURCE)
  518. return LIQUID_LEVEL_SOURCE;
  519. if (f.param_type_2 == CPT2_FLOWINGLIQUID)
  520. return getParam2() & LIQUID_LEVEL_MASK;
  521. if(f.liquid_type == LIQUID_FLOWING) // can remove if all param_type_2 set
  522. return getParam2() & LIQUID_LEVEL_MASK;
  523. if (f.param_type_2 == CPT2_LEVELED) {
  524. u8 level = getParam2() & LEVELED_MASK;
  525. if (level)
  526. return level;
  527. }
  528. // Return static value from nodedef if param2 isn't used for level
  529. if (f.leveled > f.leveled_max)
  530. return f.leveled_max;
  531. return f.leveled;
  532. }
  533. s8 MapNode::setLevel(const NodeDefManager *nodemgr, s16 level)
  534. {
  535. s8 rest = 0;
  536. const ContentFeatures &f = nodemgr->get(*this);
  537. if (f.param_type_2 == CPT2_FLOWINGLIQUID
  538. || f.liquid_type == LIQUID_FLOWING
  539. || f.liquid_type == LIQUID_SOURCE) {
  540. if (level <= 0) { // liquid can’t exist with zero level
  541. setContent(CONTENT_AIR);
  542. return 0;
  543. }
  544. if (level >= LIQUID_LEVEL_SOURCE) {
  545. rest = level - LIQUID_LEVEL_SOURCE;
  546. setContent(f.liquid_alternative_source_id);
  547. setParam2(0);
  548. } else {
  549. setContent(f.liquid_alternative_flowing_id);
  550. setParam2((level & LIQUID_LEVEL_MASK) | (getParam2() & ~LIQUID_LEVEL_MASK));
  551. }
  552. } else if (f.param_type_2 == CPT2_LEVELED) {
  553. if (level < 0) { // zero means default for a leveled nodebox
  554. rest = level;
  555. level = 0;
  556. } else if (level > f.leveled_max) {
  557. rest = level - f.leveled_max;
  558. level = f.leveled_max;
  559. }
  560. setParam2((level & LEVELED_MASK) | (getParam2() & ~LEVELED_MASK));
  561. }
  562. return rest;
  563. }
  564. s8 MapNode::addLevel(const NodeDefManager *nodemgr, s16 add)
  565. {
  566. s16 level = getLevel(nodemgr);
  567. level += add;
  568. return setLevel(nodemgr, level);
  569. }
  570. u32 MapNode::serializedLength(u8 version)
  571. {
  572. if(!ser_ver_supported(version))
  573. throw VersionMismatchException("ERROR: MapNode format not supported");
  574. if (version == 0)
  575. return 1;
  576. if (version <= 9)
  577. return 2;
  578. if (version <= 23)
  579. return 3;
  580. return 4;
  581. }
  582. void MapNode::serialize(u8 *dest, u8 version) const
  583. {
  584. if(!ser_ver_supported(version))
  585. throw VersionMismatchException("ERROR: MapNode format not supported");
  586. // Can't do this anymore; we have 16-bit dynamically allocated node IDs
  587. // in memory; conversion just won't work in this direction.
  588. if(version < 24)
  589. throw SerializationError("MapNode::serialize: serialization to "
  590. "version < 24 not possible");
  591. writeU16(dest+0, param0);
  592. writeU8(dest+2, param1);
  593. writeU8(dest+3, param2);
  594. }
  595. void MapNode::deSerialize(u8 *source, u8 version)
  596. {
  597. if(!ser_ver_supported(version))
  598. throw VersionMismatchException("ERROR: MapNode format not supported");
  599. if(version <= 21)
  600. {
  601. deSerialize_pre22(source, version);
  602. return;
  603. }
  604. if(version >= 24){
  605. param0 = readU16(source+0);
  606. param1 = readU8(source+2);
  607. param2 = readU8(source+3);
  608. }else{
  609. param0 = readU8(source+0);
  610. param1 = readU8(source+1);
  611. param2 = readU8(source+2);
  612. if(param0 > 0x7F){
  613. param0 |= ((param2&0xF0)<<4);
  614. param2 &= 0x0F;
  615. }
  616. }
  617. }
  618. Buffer<u8> MapNode::serializeBulk(int version,
  619. const MapNode *nodes, u32 nodecount,
  620. u8 content_width, u8 params_width)
  621. {
  622. if (!ser_ver_supported(version))
  623. throw VersionMismatchException("ERROR: MapNode format not supported");
  624. sanity_check(content_width == 2);
  625. sanity_check(params_width == 2);
  626. // Can't do this anymore; we have 16-bit dynamically allocated node IDs
  627. // in memory; conversion just won't work in this direction.
  628. if (version < 24)
  629. throw SerializationError("MapNode::serializeBulk: serialization to "
  630. "version < 24 not possible");
  631. Buffer<u8> databuf(nodecount * (content_width + params_width));
  632. // Writing to the buffer linearly is faster
  633. u8 *p = &databuf[0];
  634. for (u32 i = 0; i < nodecount; i++, p += 2)
  635. writeU16(p, nodes[i].param0);
  636. for (u32 i = 0; i < nodecount; i++, p++)
  637. writeU8(p, nodes[i].param1);
  638. for (u32 i = 0; i < nodecount; i++, p++)
  639. writeU8(p, nodes[i].param2);
  640. return databuf;
  641. }
  642. // Deserialize bulk node data
  643. void MapNode::deSerializeBulk(std::istream &is, int version,
  644. MapNode *nodes, u32 nodecount,
  645. u8 content_width, u8 params_width)
  646. {
  647. if(!ser_ver_supported(version))
  648. throw VersionMismatchException("ERROR: MapNode format not supported");
  649. if (version < 22
  650. || (content_width != 1 && content_width != 2)
  651. || params_width != 2)
  652. FATAL_ERROR("Deserialize bulk node data error");
  653. // read data
  654. const u32 len = nodecount * (content_width + params_width);
  655. Buffer<u8> databuf(len);
  656. is.read(reinterpret_cast<char*>(*databuf), len);
  657. // Deserialize content
  658. if(content_width == 1)
  659. {
  660. for(u32 i=0; i<nodecount; i++)
  661. nodes[i].param0 = readU8(&databuf[i]);
  662. }
  663. else if(content_width == 2)
  664. {
  665. for(u32 i=0; i<nodecount; i++)
  666. nodes[i].param0 = readU16(&databuf[i*2]);
  667. }
  668. // Deserialize param1
  669. u32 start1 = content_width * nodecount;
  670. for(u32 i=0; i<nodecount; i++)
  671. nodes[i].param1 = readU8(&databuf[start1 + i]);
  672. // Deserialize param2
  673. u32 start2 = (content_width + 1) * nodecount;
  674. if(content_width == 1)
  675. {
  676. for(u32 i=0; i<nodecount; i++) {
  677. nodes[i].param2 = readU8(&databuf[start2 + i]);
  678. if(nodes[i].param0 > 0x7F){
  679. nodes[i].param0 <<= 4;
  680. nodes[i].param0 |= (nodes[i].param2&0xF0)>>4;
  681. nodes[i].param2 &= 0x0F;
  682. }
  683. }
  684. }
  685. else if(content_width == 2)
  686. {
  687. for(u32 i=0; i<nodecount; i++)
  688. nodes[i].param2 = readU8(&databuf[start2 + i]);
  689. }
  690. }
  691. /*
  692. Legacy serialization
  693. */
  694. void MapNode::deSerialize_pre22(const u8 *source, u8 version)
  695. {
  696. if(version <= 1)
  697. {
  698. param0 = source[0];
  699. }
  700. else if(version <= 9)
  701. {
  702. param0 = source[0];
  703. param1 = source[1];
  704. }
  705. else
  706. {
  707. param0 = source[0];
  708. param1 = source[1];
  709. param2 = source[2];
  710. if(param0 > 0x7f){
  711. param0 <<= 4;
  712. param0 |= (param2&0xf0)>>4;
  713. param2 &= 0x0f;
  714. }
  715. }
  716. // Convert special values from old version to new
  717. if(version <= 19)
  718. {
  719. // In these versions, CONTENT_IGNORE and CONTENT_AIR
  720. // are 255 and 254
  721. // Version 19 is messed up with sometimes the old values and sometimes not
  722. if(param0 == 255)
  723. param0 = CONTENT_IGNORE;
  724. else if(param0 == 254)
  725. param0 = CONTENT_AIR;
  726. }
  727. // Translate to our known version
  728. *this = mapnode_translate_to_internal(*this, version);
  729. }