Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "irrlichttypes_extrabloated.h"
21 : #include "mapnode.h"
22 : #include "porting.h"
23 : #include "nodedef.h"
24 : #include "content_mapnode.h" // For mapnode_translate_*_internal
25 : #include "serialization.h" // For ser_ver_supported
26 : #include "util/serialize.h"
27 : #include "log.h"
28 : #include "util/numeric.h"
29 : #include <string>
30 : #include <sstream>
31 :
32 : static const Rotation wallmounted_to_rot[] = {
33 : ROTATE_0, ROTATE_180, ROTATE_90, ROTATE_270
34 : };
35 :
36 : static const u8 rot_to_wallmounted[] = {
37 : 2, 4, 3, 5
38 : };
39 :
40 :
41 : /*
42 : MapNode
43 : */
44 :
45 : // Create directly from a nodename
46 : // If name is unknown, sets CONTENT_IGNORE
47 0 : MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
48 : u8 a_param1, u8 a_param2)
49 : {
50 0 : content_t id = CONTENT_IGNORE;
51 0 : ndef->getId(name, id);
52 0 : param0 = id;
53 0 : param1 = a_param1;
54 0 : param2 = a_param2;
55 0 : }
56 :
57 1060 : void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
58 : {
59 : // If node doesn't contain light data, ignore this
60 1060 : if(nodemgr->get(*this).param_type != CPT_LIGHT)
61 56 : return;
62 1004 : if(bank == LIGHTBANK_DAY)
63 : {
64 182 : param1 &= 0xf0;
65 182 : param1 |= a_light & 0x0f;
66 : }
67 822 : else if(bank == LIGHTBANK_NIGHT)
68 : {
69 822 : param1 &= 0x0f;
70 822 : param1 |= (a_light & 0x0f)<<4;
71 : }
72 : else
73 : assert("Invalid light bank" == NULL);
74 : }
75 :
76 0 : bool MapNode::isLightDayNightEq(INodeDefManager *nodemgr) const
77 : {
78 0 : const ContentFeatures &f = nodemgr->get(*this);
79 : bool isEqual;
80 :
81 0 : if (f.param_type == CPT_LIGHT) {
82 0 : u8 day = MYMAX(f.light_source, param1 & 0x0f);
83 0 : u8 night = MYMAX(f.light_source, (param1 >> 4) & 0x0f);
84 0 : isEqual = day == night;
85 : } else {
86 0 : isEqual = true;
87 : }
88 :
89 0 : return isEqual;
90 : }
91 :
92 405446 : u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
93 : {
94 : // Select the brightest of [light source, propagated light]
95 405446 : const ContentFeatures &f = nodemgr->get(*this);
96 :
97 : u8 light;
98 405440 : if(f.param_type == CPT_LIGHT)
99 398828 : light = bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f;
100 : else
101 6612 : light = 0;
102 :
103 405440 : return MYMAX(f.light_source, light);
104 : }
105 :
106 27778784 : u8 MapNode::getLightNoChecks(enum LightBank bank, const ContentFeatures *f) const
107 : {
108 27778784 : return MYMAX(f->light_source,
109 : bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f);
110 : }
111 :
112 214126 : bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const
113 : {
114 : // Select the brightest of [light source, propagated light]
115 214126 : const ContentFeatures &f = nodemgr->get(*this);
116 214126 : if(f.param_type == CPT_LIGHT)
117 : {
118 214114 : lightday = param1 & 0x0f;
119 214114 : lightnight = (param1>>4)&0x0f;
120 : }
121 : else
122 : {
123 12 : lightday = 0;
124 12 : lightnight = 0;
125 : }
126 214126 : if(f.light_source > lightday)
127 172 : lightday = f.light_source;
128 214126 : if(f.light_source > lightnight)
129 175 : lightnight = f.light_source;
130 214126 : return f.param_type == CPT_LIGHT || f.light_source != 0;
131 : }
132 :
133 979129 : u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
134 : {
135 979129 : const ContentFeatures &f = nodemgr->get(*this);
136 979129 : if(f.param_type_2 == CPT2_FACEDIR)
137 64928 : return (getParam2() & 0x1F) % 24;
138 914201 : return 0;
139 : }
140 :
141 19455 : u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
142 : {
143 19455 : const ContentFeatures &f = nodemgr->get(*this);
144 19455 : if(f.param_type_2 == CPT2_WALLMOUNTED)
145 19455 : return getParam2() & 0x07;
146 0 : return 0;
147 : }
148 :
149 19455 : v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const
150 : {
151 19455 : switch(getWallMounted(nodemgr))
152 : {
153 4 : case 0: default: return v3s16(0,1,0);
154 100 : case 1: return v3s16(0,-1,0);
155 7629 : case 2: return v3s16(1,0,0);
156 6775 : case 3: return v3s16(-1,0,0);
157 2253 : case 4: return v3s16(0,0,1);
158 2694 : case 5: return v3s16(0,0,-1);
159 : }
160 : }
161 :
162 0 : void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot) {
163 0 : ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2;
164 :
165 0 : if (cpt2 == CPT2_FACEDIR) {
166 0 : if (param2 >= 4)
167 0 : return;
168 :
169 0 : u8 newrot = param2 & 3;
170 0 : param2 &= ~3;
171 0 : param2 |= (newrot + rot) & 3;
172 0 : } else if (cpt2 == CPT2_WALLMOUNTED) {
173 0 : u8 wmountface = (param2 & 7);
174 0 : if (wmountface <= 1)
175 0 : return;
176 :
177 0 : Rotation oldrot = wallmounted_to_rot[wmountface - 2];
178 0 : param2 &= ~7;
179 0 : param2 |= rot_to_wallmounted[(oldrot - rot) & 3];
180 : }
181 : }
182 :
183 493832 : static std::vector<aabb3f> transformNodeBox(const MapNode &n,
184 : const NodeBox &nodebox, INodeDefManager *nodemgr)
185 : {
186 493832 : std::vector<aabb3f> boxes;
187 493832 : if(nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED)
188 : {
189 12595 : const std::vector<aabb3f> &fixed = nodebox.fixed;
190 12595 : int facedir = n.getFaceDir(nodemgr);
191 12595 : u8 axisdir = facedir>>2;
192 12595 : facedir&=0x03;
193 69866 : for(std::vector<aabb3f>::const_iterator
194 12595 : i = fixed.begin();
195 54974 : i != fixed.end(); i++)
196 : {
197 14892 : aabb3f box = *i;
198 :
199 14892 : if (nodebox.type == NODEBOX_LEVELED) {
200 0 : box.MaxEdge.Y = -BS/2 + BS*((float)1/LEVELED_MAX) * n.getLevel(nodemgr);
201 : }
202 :
203 14892 : switch (axisdir)
204 : {
205 : case 0:
206 14892 : if(facedir == 1)
207 : {
208 1844 : box.MinEdge.rotateXZBy(-90);
209 1844 : box.MaxEdge.rotateXZBy(-90);
210 : }
211 13048 : else if(facedir == 2)
212 : {
213 2391 : box.MinEdge.rotateXZBy(180);
214 2391 : box.MaxEdge.rotateXZBy(180);
215 : }
216 10657 : else if(facedir == 3)
217 : {
218 457 : box.MinEdge.rotateXZBy(90);
219 457 : box.MaxEdge.rotateXZBy(90);
220 : }
221 14892 : break;
222 : case 1: // z+
223 0 : box.MinEdge.rotateYZBy(90);
224 0 : box.MaxEdge.rotateYZBy(90);
225 0 : if(facedir == 1)
226 : {
227 0 : box.MinEdge.rotateXYBy(90);
228 0 : box.MaxEdge.rotateXYBy(90);
229 : }
230 0 : else if(facedir == 2)
231 : {
232 0 : box.MinEdge.rotateXYBy(180);
233 0 : box.MaxEdge.rotateXYBy(180);
234 : }
235 0 : else if(facedir == 3)
236 : {
237 0 : box.MinEdge.rotateXYBy(-90);
238 0 : box.MaxEdge.rotateXYBy(-90);
239 : }
240 0 : break;
241 : case 2: //z-
242 0 : box.MinEdge.rotateYZBy(-90);
243 0 : box.MaxEdge.rotateYZBy(-90);
244 0 : if(facedir == 1)
245 : {
246 0 : box.MinEdge.rotateXYBy(-90);
247 0 : box.MaxEdge.rotateXYBy(-90);
248 : }
249 0 : else if(facedir == 2)
250 : {
251 0 : box.MinEdge.rotateXYBy(180);
252 0 : box.MaxEdge.rotateXYBy(180);
253 : }
254 0 : else if(facedir == 3)
255 : {
256 0 : box.MinEdge.rotateXYBy(90);
257 0 : box.MaxEdge.rotateXYBy(90);
258 : }
259 0 : break;
260 : case 3: //x+
261 0 : box.MinEdge.rotateXYBy(-90);
262 0 : box.MaxEdge.rotateXYBy(-90);
263 0 : if(facedir == 1)
264 : {
265 0 : box.MinEdge.rotateYZBy(90);
266 0 : box.MaxEdge.rotateYZBy(90);
267 : }
268 0 : else if(facedir == 2)
269 : {
270 0 : box.MinEdge.rotateYZBy(180);
271 0 : box.MaxEdge.rotateYZBy(180);
272 : }
273 0 : else if(facedir == 3)
274 : {
275 0 : box.MinEdge.rotateYZBy(-90);
276 0 : box.MaxEdge.rotateYZBy(-90);
277 : }
278 0 : break;
279 : case 4: //x-
280 0 : box.MinEdge.rotateXYBy(90);
281 0 : box.MaxEdge.rotateXYBy(90);
282 0 : if(facedir == 1)
283 : {
284 0 : box.MinEdge.rotateYZBy(-90);
285 0 : box.MaxEdge.rotateYZBy(-90);
286 : }
287 0 : else if(facedir == 2)
288 : {
289 0 : box.MinEdge.rotateYZBy(180);
290 0 : box.MaxEdge.rotateYZBy(180);
291 : }
292 0 : else if(facedir == 3)
293 : {
294 0 : box.MinEdge.rotateYZBy(90);
295 0 : box.MaxEdge.rotateYZBy(90);
296 : }
297 0 : break;
298 : case 5:
299 0 : box.MinEdge.rotateXYBy(-180);
300 0 : box.MaxEdge.rotateXYBy(-180);
301 0 : if(facedir == 1)
302 : {
303 0 : box.MinEdge.rotateXZBy(90);
304 0 : box.MaxEdge.rotateXZBy(90);
305 : }
306 0 : else if(facedir == 2)
307 : {
308 0 : box.MinEdge.rotateXZBy(180);
309 0 : box.MaxEdge.rotateXZBy(180);
310 : }
311 0 : else if(facedir == 3)
312 : {
313 0 : box.MinEdge.rotateXZBy(-90);
314 0 : box.MaxEdge.rotateXZBy(-90);
315 : }
316 0 : break;
317 : default:
318 0 : break;
319 : }
320 14892 : box.repair();
321 14892 : boxes.push_back(box);
322 12595 : }
323 : }
324 481237 : else if(nodebox.type == NODEBOX_WALLMOUNTED)
325 : {
326 2112 : v3s16 dir = n.getWallMountedDir(nodemgr);
327 :
328 : // top
329 2112 : if(dir == v3s16(0,1,0))
330 : {
331 4 : boxes.push_back(nodebox.wall_top);
332 : }
333 : // bottom
334 2108 : else if(dir == v3s16(0,-1,0))
335 : {
336 44 : boxes.push_back(nodebox.wall_bottom);
337 : }
338 : // side
339 : else
340 : {
341 : v3f vertices[2] =
342 : {
343 : nodebox.wall_side.MinEdge,
344 : nodebox.wall_side.MaxEdge
345 2064 : };
346 :
347 6192 : for(s32 i=0; i<2; i++)
348 : {
349 4128 : if(dir == v3s16(-1,0,0))
350 3138 : vertices[i].rotateXZBy(0);
351 4128 : if(dir == v3s16(1,0,0))
352 528 : vertices[i].rotateXZBy(180);
353 4128 : if(dir == v3s16(0,0,-1))
354 378 : vertices[i].rotateXZBy(90);
355 4128 : if(dir == v3s16(0,0,1))
356 84 : vertices[i].rotateXZBy(-90);
357 : }
358 :
359 2064 : aabb3f box = aabb3f(vertices[0]);
360 2064 : box.addInternalPoint(vertices[1]);
361 2064 : boxes.push_back(box);
362 : }
363 : }
364 : else // NODEBOX_REGULAR
365 : {
366 479125 : boxes.push_back(aabb3f(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2));
367 : }
368 493832 : return boxes;
369 : }
370 :
371 166 : std::vector<aabb3f> MapNode::getNodeBoxes(INodeDefManager *nodemgr) const
372 : {
373 166 : const ContentFeatures &f = nodemgr->get(*this);
374 166 : return transformNodeBox(*this, f.node_box, nodemgr);
375 : }
376 :
377 303424 : std::vector<aabb3f> MapNode::getCollisionBoxes(INodeDefManager *nodemgr) const
378 : {
379 303424 : const ContentFeatures &f = nodemgr->get(*this);
380 303424 : if (f.collision_box.fixed.empty())
381 303290 : return transformNodeBox(*this, f.node_box, nodemgr);
382 : else
383 134 : return transformNodeBox(*this, f.collision_box, nodemgr);
384 : }
385 :
386 190242 : std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
387 : {
388 190242 : const ContentFeatures &f = nodemgr->get(*this);
389 190242 : return transformNodeBox(*this, f.selection_box, nodemgr);
390 : }
391 :
392 0 : u8 MapNode::getMaxLevel(INodeDefManager *nodemgr) const
393 : {
394 0 : const ContentFeatures &f = nodemgr->get(*this);
395 : // todo: after update in all games leave only if (f.param_type_2 ==
396 0 : if( f.liquid_type == LIQUID_FLOWING || f.param_type_2 == CPT2_FLOWINGLIQUID)
397 0 : return LIQUID_LEVEL_MAX;
398 0 : if(f.leveled || f.param_type_2 == CPT2_LEVELED)
399 0 : return LEVELED_MAX;
400 0 : return 0;
401 : }
402 :
403 0 : u8 MapNode::getLevel(INodeDefManager *nodemgr) const
404 : {
405 0 : const ContentFeatures &f = nodemgr->get(*this);
406 : // todo: after update in all games leave only if (f.param_type_2 ==
407 0 : if(f.liquid_type == LIQUID_SOURCE)
408 0 : return LIQUID_LEVEL_SOURCE;
409 0 : if (f.param_type_2 == CPT2_FLOWINGLIQUID)
410 0 : return getParam2() & LIQUID_LEVEL_MASK;
411 0 : if(f.liquid_type == LIQUID_FLOWING) // can remove if all param_type_2 setted
412 0 : return getParam2() & LIQUID_LEVEL_MASK;
413 0 : if(f.leveled || f.param_type_2 == CPT2_LEVELED) {
414 0 : u8 level = getParam2() & LEVELED_MASK;
415 0 : if(level)
416 0 : return level;
417 0 : if(f.leveled > LEVELED_MAX)
418 0 : return LEVELED_MAX;
419 0 : return f.leveled; //default
420 : }
421 0 : return 0;
422 : }
423 :
424 0 : u8 MapNode::setLevel(INodeDefManager *nodemgr, s8 level)
425 : {
426 0 : u8 rest = 0;
427 0 : if (level < 1) {
428 0 : setContent(CONTENT_AIR);
429 0 : return 0;
430 : }
431 0 : const ContentFeatures &f = nodemgr->get(*this);
432 0 : if (f.param_type_2 == CPT2_FLOWINGLIQUID
433 0 : || f.liquid_type == LIQUID_FLOWING
434 0 : || f.liquid_type == LIQUID_SOURCE) {
435 0 : if (level >= LIQUID_LEVEL_SOURCE) {
436 0 : rest = level - LIQUID_LEVEL_SOURCE;
437 0 : setContent(nodemgr->getId(f.liquid_alternative_source));
438 : } else {
439 0 : setContent(nodemgr->getId(f.liquid_alternative_flowing));
440 0 : setParam2(level & LIQUID_LEVEL_MASK);
441 : }
442 0 : } else if (f.leveled || f.param_type_2 == CPT2_LEVELED) {
443 0 : if (level > LEVELED_MAX) {
444 0 : rest = level - LEVELED_MAX;
445 0 : level = LEVELED_MAX;
446 : }
447 0 : setParam2(level & LEVELED_MASK);
448 : }
449 0 : return rest;
450 : }
451 :
452 0 : u8 MapNode::addLevel(INodeDefManager *nodemgr, s8 add)
453 : {
454 0 : s8 level = getLevel(nodemgr);
455 0 : if (add == 0) level = 1;
456 0 : level += add;
457 0 : return setLevel(nodemgr, level);
458 : }
459 :
460 98 : u32 MapNode::serializedLength(u8 version)
461 : {
462 98 : if(!ser_ver_supported(version))
463 0 : throw VersionMismatchException("ERROR: MapNode format not supported");
464 :
465 98 : if(version == 0)
466 0 : return 1;
467 98 : else if(version <= 9)
468 0 : return 2;
469 98 : else if(version <= 23)
470 0 : return 3;
471 : else
472 98 : return 4;
473 : }
474 0 : void MapNode::serialize(u8 *dest, u8 version)
475 : {
476 0 : if(!ser_ver_supported(version))
477 0 : throw VersionMismatchException("ERROR: MapNode format not supported");
478 :
479 : // Can't do this anymore; we have 16-bit dynamically allocated node IDs
480 : // in memory; conversion just won't work in this direction.
481 0 : if(version < 24)
482 : throw SerializationError("MapNode::serialize: serialization to "
483 0 : "version < 24 not possible");
484 :
485 0 : writeU16(dest+0, param0);
486 0 : writeU8(dest+2, param1);
487 0 : writeU8(dest+3, param2);
488 0 : }
489 49 : void MapNode::deSerialize(u8 *source, u8 version)
490 : {
491 49 : if(!ser_ver_supported(version))
492 0 : throw VersionMismatchException("ERROR: MapNode format not supported");
493 :
494 49 : if(version <= 21)
495 : {
496 0 : deSerialize_pre22(source, version);
497 0 : return;
498 : }
499 :
500 49 : if(version >= 24){
501 49 : param0 = readU16(source+0);
502 49 : param1 = readU8(source+2);
503 49 : param2 = readU8(source+3);
504 : }else{
505 0 : param0 = readU8(source+0);
506 0 : param1 = readU8(source+1);
507 0 : param2 = readU8(source+2);
508 0 : if(param0 > 0x7F){
509 0 : param0 |= ((param2&0xF0)<<4);
510 0 : param2 &= 0x0F;
511 : }
512 : }
513 : }
514 0 : void MapNode::serializeBulk(std::ostream &os, int version,
515 : const MapNode *nodes, u32 nodecount,
516 : u8 content_width, u8 params_width, bool compressed)
517 : {
518 0 : if(!ser_ver_supported(version))
519 0 : throw VersionMismatchException("ERROR: MapNode format not supported");
520 :
521 0 : sanity_check(content_width == 2);
522 0 : sanity_check(params_width == 2);
523 :
524 : // Can't do this anymore; we have 16-bit dynamically allocated node IDs
525 : // in memory; conversion just won't work in this direction.
526 0 : if(version < 24)
527 : throw SerializationError("MapNode::serializeBulk: serialization to "
528 0 : "version < 24 not possible");
529 :
530 0 : SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
531 :
532 : // Serialize content
533 0 : for(u32 i=0; i<nodecount; i++)
534 0 : writeU16(&databuf[i*2], nodes[i].param0);
535 :
536 : // Serialize param1
537 0 : u32 start1 = content_width * nodecount;
538 0 : for(u32 i=0; i<nodecount; i++)
539 0 : writeU8(&databuf[start1 + i], nodes[i].param1);
540 :
541 : // Serialize param2
542 0 : u32 start2 = (content_width + 1) * nodecount;
543 0 : for(u32 i=0; i<nodecount; i++)
544 0 : writeU8(&databuf[start2 + i], nodes[i].param2);
545 :
546 : /*
547 : Compress data to output stream
548 : */
549 :
550 0 : if(compressed)
551 : {
552 0 : compressZlib(databuf, os);
553 : }
554 : else
555 : {
556 0 : os.write((const char*) &databuf[0], databuf.getSize());
557 : }
558 0 : }
559 :
560 : // Deserialize bulk node data
561 786 : void MapNode::deSerializeBulk(std::istream &is, int version,
562 : MapNode *nodes, u32 nodecount,
563 : u8 content_width, u8 params_width, bool compressed)
564 : {
565 786 : if(!ser_ver_supported(version))
566 0 : throw VersionMismatchException("ERROR: MapNode format not supported");
567 :
568 786 : if (version < 22
569 786 : || (content_width != 1 && content_width != 2)
570 786 : || params_width != 2)
571 0 : FATAL_ERROR("Deserialize bulk node data error");
572 :
573 : // Uncompress or read data
574 786 : u32 len = nodecount * (content_width + params_width);
575 1572 : SharedBuffer<u8> databuf(len);
576 786 : if(compressed)
577 : {
578 1572 : std::ostringstream os(std::ios_base::binary);
579 786 : decompressZlib(is, os);
580 1572 : std::string s = os.str();
581 786 : if(s.size() != len)
582 : throw SerializationError("deSerializeBulkNodes: "
583 0 : "decompress resulted in invalid size");
584 786 : memcpy(&databuf[0], s.c_str(), len);
585 : }
586 : else
587 : {
588 0 : is.read((char*) &databuf[0], len);
589 0 : if(is.eof() || is.fail())
590 : throw SerializationError("deSerializeBulkNodes: "
591 0 : "failed to read bulk node data");
592 : }
593 :
594 : // Deserialize content
595 786 : if(content_width == 1)
596 : {
597 0 : for(u32 i=0; i<nodecount; i++)
598 0 : nodes[i].param0 = readU8(&databuf[i]);
599 : }
600 786 : else if(content_width == 2)
601 : {
602 3220242 : for(u32 i=0; i<nodecount; i++)
603 3219456 : nodes[i].param0 = readU16(&databuf[i*2]);
604 : }
605 :
606 : // Deserialize param1
607 786 : u32 start1 = content_width * nodecount;
608 3220242 : for(u32 i=0; i<nodecount; i++)
609 3219456 : nodes[i].param1 = readU8(&databuf[start1 + i]);
610 :
611 : // Deserialize param2
612 786 : u32 start2 = (content_width + 1) * nodecount;
613 786 : if(content_width == 1)
614 : {
615 0 : for(u32 i=0; i<nodecount; i++) {
616 0 : nodes[i].param2 = readU8(&databuf[start2 + i]);
617 0 : if(nodes[i].param0 > 0x7F){
618 0 : nodes[i].param0 <<= 4;
619 0 : nodes[i].param0 |= (nodes[i].param2&0xF0)>>4;
620 0 : nodes[i].param2 &= 0x0F;
621 : }
622 : }
623 : }
624 786 : else if(content_width == 2)
625 : {
626 3220242 : for(u32 i=0; i<nodecount; i++)
627 3219456 : nodes[i].param2 = readU8(&databuf[start2 + i]);
628 : }
629 786 : }
630 :
631 : /*
632 : Legacy serialization
633 : */
634 0 : void MapNode::deSerialize_pre22(u8 *source, u8 version)
635 : {
636 0 : if(version <= 1)
637 : {
638 0 : param0 = source[0];
639 : }
640 0 : else if(version <= 9)
641 : {
642 0 : param0 = source[0];
643 0 : param1 = source[1];
644 : }
645 : else
646 : {
647 0 : param0 = source[0];
648 0 : param1 = source[1];
649 0 : param2 = source[2];
650 0 : if(param0 > 0x7f){
651 0 : param0 <<= 4;
652 0 : param0 |= (param2&0xf0)>>4;
653 0 : param2 &= 0x0f;
654 : }
655 : }
656 :
657 : // Convert special values from old version to new
658 0 : if(version <= 19)
659 : {
660 : // In these versions, CONTENT_IGNORE and CONTENT_AIR
661 : // are 255 and 254
662 : // Version 19 is fucked up with sometimes the old values and sometimes not
663 0 : if(param0 == 255)
664 0 : param0 = CONTENT_IGNORE;
665 0 : else if(param0 == 254)
666 0 : param0 = CONTENT_AIR;
667 : }
668 :
669 : // Translate to our known version
670 0 : *this = mapnode_translate_to_internal(*this, version);
671 3 : }
|