LCOV - code coverage report
Current view: top level - src - mapnode.cpp (source / functions) Hit Total Coverage
Test: report Lines: 144 360 40.0 %
Date: 2015-07-11 18:23:49 Functions: 16 26 61.5 %

          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 : }

Generated by: LCOV version 1.11