LCOV - code coverage report
Current view: top level - src - nodedef.cpp (source / functions) Hit Total Coverage
Test: report Lines: 446 966 46.2 %
Date: 2015-07-11 18:23:49 Functions: 29 51 56.9 %

          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 "nodedef.h"
      21             : 
      22             : #include "itemdef.h"
      23             : #ifndef SERVER
      24             : #include "client/tile.h"
      25             : #include "mesh.h"
      26             : #include <IMeshManipulator.h>
      27             : #endif
      28             : #include "log.h"
      29             : #include "settings.h"
      30             : #include "nameidmapping.h"
      31             : #include "util/numeric.h"
      32             : #include "util/serialize.h"
      33             : #include "exceptions.h"
      34             : #include "debug.h"
      35             : #include "gamedef.h"
      36             : #include <fstream> // Used in applyTextureOverrides()
      37             : 
      38             : /*
      39             :         NodeBox
      40             : */
      41             : 
      42       46032 : void NodeBox::reset()
      43             : {
      44       46032 :         type = NODEBOX_REGULAR;
      45             :         // default is empty
      46       46032 :         fixed.clear();
      47             :         // default is sign/ladder-like
      48       46032 :         wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
      49       46032 :         wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
      50       46032 :         wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
      51       46032 : }
      52             : 
      53           0 : void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
      54             : {
      55           0 :         int version = protocol_version >= 21 ? 2 : 1;
      56           0 :         writeU8(os, version);
      57             : 
      58           0 :         if (version == 1 && type == NODEBOX_LEVELED)
      59           0 :                 writeU8(os, NODEBOX_FIXED);
      60             :         else
      61           0 :                 writeU8(os, type);
      62             : 
      63           0 :         if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
      64             :         {
      65           0 :                 writeU16(os, fixed.size());
      66           0 :                 for(std::vector<aabb3f>::const_iterator
      67           0 :                                 i = fixed.begin();
      68           0 :                                 i != fixed.end(); i++)
      69             :                 {
      70           0 :                         writeV3F1000(os, i->MinEdge);
      71           0 :                         writeV3F1000(os, i->MaxEdge);
      72           0 :                 }
      73             :         }
      74           0 :         else if(type == NODEBOX_WALLMOUNTED)
      75             :         {
      76           0 :                 writeV3F1000(os, wall_top.MinEdge);
      77           0 :                 writeV3F1000(os, wall_top.MaxEdge);
      78           0 :                 writeV3F1000(os, wall_bottom.MinEdge);
      79           0 :                 writeV3F1000(os, wall_bottom.MaxEdge);
      80           0 :                 writeV3F1000(os, wall_side.MinEdge);
      81           0 :                 writeV3F1000(os, wall_side.MaxEdge);
      82             :         }
      83           0 : }
      84             : 
      85       15576 : void NodeBox::deSerialize(std::istream &is)
      86             : {
      87       15576 :         int version = readU8(is);
      88       15576 :         if(version < 1 || version > 2)
      89           0 :                 throw SerializationError("unsupported NodeBox version");
      90             : 
      91       15576 :         reset();
      92             : 
      93       15576 :         type = (enum NodeBoxType)readU8(is);
      94             : 
      95       15576 :         if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
      96             :         {
      97        9103 :                 u16 fixed_count = readU16(is);
      98       50977 :                 while(fixed_count--)
      99             :                 {
     100       20937 :                         aabb3f box;
     101       20937 :                         box.MinEdge = readV3F1000(is);
     102       20937 :                         box.MaxEdge = readV3F1000(is);
     103       20937 :                         fixed.push_back(box);
     104        9103 :                 }
     105             :         }
     106        6473 :         else if(type == NODEBOX_WALLMOUNTED)
     107             :         {
     108          69 :                 wall_top.MinEdge = readV3F1000(is);
     109          69 :                 wall_top.MaxEdge = readV3F1000(is);
     110          69 :                 wall_bottom.MinEdge = readV3F1000(is);
     111          69 :                 wall_bottom.MaxEdge = readV3F1000(is);
     112          69 :                 wall_side.MinEdge = readV3F1000(is);
     113          69 :                 wall_side.MaxEdge = readV3F1000(is);
     114             :         }
     115       15576 : }
     116             : 
     117             : /*
     118             :         TileDef
     119             : */
     120             : 
     121           0 : void TileDef::serialize(std::ostream &os, u16 protocol_version) const
     122             : {
     123           0 :         if(protocol_version >= 17)
     124           0 :                 writeU8(os, 1);
     125             :         else
     126           0 :                 writeU8(os, 0);
     127           0 :         os<<serializeString(name);
     128           0 :         writeU8(os, animation.type);
     129           0 :         writeU16(os, animation.aspect_w);
     130           0 :         writeU16(os, animation.aspect_h);
     131           0 :         writeF1000(os, animation.length);
     132           0 :         if(protocol_version >= 17)
     133           0 :                 writeU8(os, backface_culling);
     134           0 : }
     135             : 
     136       62304 : void TileDef::deSerialize(std::istream &is)
     137             : {
     138       62304 :         int version = readU8(is);
     139       62304 :         name = deSerializeString(is);
     140       62304 :         animation.type = (TileAnimationType)readU8(is);
     141       62304 :         animation.aspect_w = readU16(is);
     142       62304 :         animation.aspect_h = readU16(is);
     143       62304 :         animation.length = readF1000(is);
     144       62304 :         if(version >= 1)
     145       62304 :                 backface_culling = readU8(is);
     146       62304 : }
     147             : 
     148             : /*
     149             :         SimpleSoundSpec serialization
     150             : */
     151             : 
     152           0 : static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
     153             :                 std::ostream &os)
     154             : {
     155           0 :         os<<serializeString(ss.name);
     156           0 :         writeF1000(os, ss.gain);
     157           0 : }
     158       15576 : static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
     159             : {
     160       15576 :         ss.name = deSerializeString(is);
     161       15576 :         ss.gain = readF1000(is);
     162       15576 : }
     163             : 
     164             : /*
     165             :         ContentFeatures
     166             : */
     167             : 
     168        5076 : ContentFeatures::ContentFeatures()
     169             : {
     170        5076 :         reset();
     171        5076 : }
     172             : 
     173       62054 : ContentFeatures::~ContentFeatures()
     174             : {
     175       62054 : }
     176             : 
     177        5076 : void ContentFeatures::reset()
     178             : {
     179             :         /*
     180             :                 Cached stuff
     181             :         */
     182             : #ifndef SERVER
     183        5076 :         solidness = 2;
     184        5076 :         visual_solidness = 0;
     185        5076 :         backface_culling = true;
     186             : #endif
     187        5076 :         has_on_construct = false;
     188        5076 :         has_on_destruct = false;
     189        5076 :         has_after_destruct = false;
     190             :         /*
     191             :                 Actual data
     192             : 
     193             :                 NOTE: Most of this is always overridden by the default values given
     194             :                       in builtin.lua
     195             :         */
     196        5076 :         name = "";
     197        5076 :         groups.clear();
     198             :         // Unknown nodes can be dug
     199        5076 :         groups["dig_immediate"] = 2;
     200        5076 :         drawtype = NDT_NORMAL;
     201        5076 :         mesh = "";
     202             : #ifndef SERVER
     203      126900 :         for(u32 i = 0; i < 24; i++)
     204      121824 :                 mesh_ptr[i] = NULL;
     205        5076 :         minimap_color = video::SColor(0, 0, 0, 0);
     206             : #endif
     207        5076 :         visual_scale = 1.0;
     208       35532 :         for(u32 i = 0; i < 6; i++)
     209       30456 :                 tiledef[i] = TileDef();
     210       35532 :         for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
     211       30456 :                 tiledef_special[j] = TileDef();
     212        5076 :         alpha = 255;
     213        5076 :         post_effect_color = video::SColor(0, 0, 0, 0);
     214        5076 :         param_type = CPT_NONE;
     215        5076 :         param_type_2 = CPT2_NONE;
     216        5076 :         is_ground_content = false;
     217        5076 :         light_propagates = false;
     218        5076 :         sunlight_propagates = false;
     219        5076 :         walkable = true;
     220        5076 :         pointable = true;
     221        5076 :         diggable = true;
     222        5076 :         climbable = false;
     223        5076 :         buildable_to = false;
     224        5076 :         rightclickable = true;
     225        5076 :         leveled = 0;
     226        5076 :         liquid_type = LIQUID_NONE;
     227        5076 :         liquid_alternative_flowing = "";
     228        5076 :         liquid_alternative_source = "";
     229        5076 :         liquid_viscosity = 0;
     230        5076 :         liquid_renewable = true;
     231        5076 :         liquid_range = LIQUID_LEVEL_MAX+1;
     232        5076 :         drowning = 0;
     233        5076 :         light_source = 0;
     234        5076 :         damage_per_second = 0;
     235        5076 :         node_box = NodeBox();
     236        5076 :         selection_box = NodeBox();
     237        5076 :         collision_box = NodeBox();
     238        5076 :         waving = 0;
     239        5076 :         legacy_facedir_simple = false;
     240        5076 :         legacy_wallmounted = false;
     241        5076 :         sound_footstep = SimpleSoundSpec();
     242        5076 :         sound_dig = SimpleSoundSpec("__group");
     243        5076 :         sound_dug = SimpleSoundSpec();
     244        5076 : }
     245             : 
     246           0 : void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
     247             : {
     248           0 :         if(protocol_version < 24){
     249           0 :                 serializeOld(os, protocol_version);
     250           0 :                 return;
     251             :         }
     252             : 
     253           0 :         writeU8(os, 7); // version
     254           0 :         os<<serializeString(name);
     255           0 :         writeU16(os, groups.size());
     256           0 :         for(ItemGroupList::const_iterator
     257           0 :                         i = groups.begin(); i != groups.end(); i++){
     258           0 :                 os<<serializeString(i->first);
     259           0 :                 writeS16(os, i->second);
     260             :         }
     261           0 :         writeU8(os, drawtype);
     262           0 :         writeF1000(os, visual_scale);
     263           0 :         writeU8(os, 6);
     264           0 :         for(u32 i = 0; i < 6; i++)
     265           0 :                 tiledef[i].serialize(os, protocol_version);
     266           0 :         writeU8(os, CF_SPECIAL_COUNT);
     267           0 :         for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
     268           0 :                 tiledef_special[i].serialize(os, protocol_version);
     269             :         }
     270           0 :         writeU8(os, alpha);
     271           0 :         writeU8(os, post_effect_color.getAlpha());
     272           0 :         writeU8(os, post_effect_color.getRed());
     273           0 :         writeU8(os, post_effect_color.getGreen());
     274           0 :         writeU8(os, post_effect_color.getBlue());
     275           0 :         writeU8(os, param_type);
     276           0 :         writeU8(os, param_type_2);
     277           0 :         writeU8(os, is_ground_content);
     278           0 :         writeU8(os, light_propagates);
     279           0 :         writeU8(os, sunlight_propagates);
     280           0 :         writeU8(os, walkable);
     281           0 :         writeU8(os, pointable);
     282           0 :         writeU8(os, diggable);
     283           0 :         writeU8(os, climbable);
     284           0 :         writeU8(os, buildable_to);
     285           0 :         os<<serializeString(""); // legacy: used to be metadata_name
     286           0 :         writeU8(os, liquid_type);
     287           0 :         os<<serializeString(liquid_alternative_flowing);
     288           0 :         os<<serializeString(liquid_alternative_source);
     289           0 :         writeU8(os, liquid_viscosity);
     290           0 :         writeU8(os, liquid_renewable);
     291           0 :         writeU8(os, light_source);
     292           0 :         writeU32(os, damage_per_second);
     293           0 :         node_box.serialize(os, protocol_version);
     294           0 :         selection_box.serialize(os, protocol_version);
     295           0 :         writeU8(os, legacy_facedir_simple);
     296           0 :         writeU8(os, legacy_wallmounted);
     297           0 :         serializeSimpleSoundSpec(sound_footstep, os);
     298           0 :         serializeSimpleSoundSpec(sound_dig, os);
     299           0 :         serializeSimpleSoundSpec(sound_dug, os);
     300           0 :         writeU8(os, rightclickable);
     301           0 :         writeU8(os, drowning);
     302           0 :         writeU8(os, leveled);
     303           0 :         writeU8(os, liquid_range);
     304           0 :         writeU8(os, waving);
     305             :         // Stuff below should be moved to correct place in a version that otherwise changes
     306             :         // the protocol version
     307           0 :         os<<serializeString(mesh);
     308           0 :         collision_box.serialize(os, protocol_version);
     309             : }
     310             : 
     311        5192 : void ContentFeatures::deSerialize(std::istream &is)
     312             : {
     313        5192 :         int version = readU8(is);
     314        5192 :         if(version != 7){
     315           0 :                 deSerializeOld(is, version);
     316           0 :                 return;
     317             :         }
     318             : 
     319        5192 :         name = deSerializeString(is);
     320        5192 :         groups.clear();
     321        5192 :         u32 groups_size = readU16(is);
     322       22204 :         for(u32 i = 0; i < groups_size; i++){
     323       34024 :                 std::string name = deSerializeString(is);
     324       17012 :                 int value = readS16(is);
     325       17012 :                 groups[name] = value;
     326             :         }
     327        5192 :         drawtype = (enum NodeDrawType)readU8(is);
     328        5192 :         visual_scale = readF1000(is);
     329        5192 :         if(readU8(is) != 6)
     330           0 :                 throw SerializationError("unsupported tile count");
     331       36344 :         for(u32 i = 0; i < 6; i++)
     332       31152 :                 tiledef[i].deSerialize(is);
     333        5192 :         if(readU8(is) != CF_SPECIAL_COUNT)
     334           0 :                 throw SerializationError("unsupported CF_SPECIAL_COUNT");
     335       36344 :         for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
     336       31152 :                 tiledef_special[i].deSerialize(is);
     337        5192 :         alpha = readU8(is);
     338        5192 :         post_effect_color.setAlpha(readU8(is));
     339        5192 :         post_effect_color.setRed(readU8(is));
     340        5192 :         post_effect_color.setGreen(readU8(is));
     341        5192 :         post_effect_color.setBlue(readU8(is));
     342        5192 :         param_type = (enum ContentParamType)readU8(is);
     343        5192 :         param_type_2 = (enum ContentParamType2)readU8(is);
     344        5192 :         is_ground_content = readU8(is);
     345        5192 :         light_propagates = readU8(is);
     346        5192 :         sunlight_propagates = readU8(is);
     347        5192 :         walkable = readU8(is);
     348        5192 :         pointable = readU8(is);
     349        5192 :         diggable = readU8(is);
     350        5192 :         climbable = readU8(is);
     351        5192 :         buildable_to = readU8(is);
     352        5192 :         deSerializeString(is); // legacy: used to be metadata_name
     353        5192 :         liquid_type = (enum LiquidType)readU8(is);
     354        5192 :         liquid_alternative_flowing = deSerializeString(is);
     355        5192 :         liquid_alternative_source = deSerializeString(is);
     356        5192 :         liquid_viscosity = readU8(is);
     357        5192 :         liquid_renewable = readU8(is);
     358        5192 :         light_source = readU8(is);
     359        5192 :         damage_per_second = readU32(is);
     360        5192 :         node_box.deSerialize(is);
     361        5192 :         selection_box.deSerialize(is);
     362        5192 :         legacy_facedir_simple = readU8(is);
     363        5192 :         legacy_wallmounted = readU8(is);
     364        5192 :         deSerializeSimpleSoundSpec(sound_footstep, is);
     365        5192 :         deSerializeSimpleSoundSpec(sound_dig, is);
     366        5192 :         deSerializeSimpleSoundSpec(sound_dug, is);
     367        5192 :         rightclickable = readU8(is);
     368        5192 :         drowning = readU8(is);
     369        5192 :         leveled = readU8(is);
     370        5192 :         liquid_range = readU8(is);
     371        5192 :         waving = readU8(is);
     372             :         // If you add anything here, insert it primarily inside the try-catch
     373             :         // block to not need to increase the version.
     374             :         try{
     375             :                 // Stuff below should be moved to correct place in a version that
     376             :                 // otherwise changes the protocol version
     377        5192 :         mesh = deSerializeString(is);
     378        5192 :         collision_box.deSerialize(is);
     379           0 :         }catch(SerializationError &e) {};
     380             : }
     381             : 
     382             : /*
     383             :         CNodeDefManager
     384             : */
     385             : 
     386           0 : class CNodeDefManager: public IWritableNodeDefManager {
     387             : public:
     388             :         CNodeDefManager();
     389             :         virtual ~CNodeDefManager();
     390             :         void clear();
     391             :         virtual IWritableNodeDefManager *clone();
     392             :         inline virtual const ContentFeatures& get(content_t c) const;
     393             :         inline virtual const ContentFeatures& get(const MapNode &n) const;
     394             :         virtual bool getId(const std::string &name, content_t &result) const;
     395             :         virtual content_t getId(const std::string &name) const;
     396             :         virtual void getIds(const std::string &name, std::set<content_t> &result) const;
     397             :         virtual const ContentFeatures& get(const std::string &name) const;
     398             :         content_t allocateId();
     399             :         virtual content_t set(const std::string &name, const ContentFeatures &def);
     400             :         virtual content_t allocateDummy(const std::string &name);
     401             :         virtual void updateAliases(IItemDefManager *idef);
     402             :         virtual void applyTextureOverrides(const std::string &override_filepath);
     403             :         virtual void updateTextures(IGameDef *gamedef,
     404             :                 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
     405             :                 void *progress_cbk_args);
     406             :         void serialize(std::ostream &os, u16 protocol_version) const;
     407             :         void deSerialize(std::istream &is);
     408             : 
     409             :         inline virtual bool getNodeRegistrationStatus() const;
     410             :         inline virtual void setNodeRegistrationStatus(bool completed);
     411             : 
     412             :         virtual void pendNodeResolve(NodeResolver *nr);
     413             :         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
     414             :         virtual void runNodeResolveCallbacks();
     415             :         virtual void resetNodeResolveState();
     416             : 
     417             : private:
     418             :         void addNameIdMapping(content_t i, std::string name);
     419             : #ifndef SERVER
     420             :         void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
     421             :                 u32 shader_id, bool use_normal_texture, bool backface_culling,
     422             :                 u8 alpha, u8 material_type);
     423             : #endif
     424             : 
     425             :         // Features indexed by id
     426             :         std::vector<ContentFeatures> m_content_features;
     427             : 
     428             :         // A mapping for fast converting back and forth between names and ids
     429             :         NameIdMapping m_name_id_mapping;
     430             : 
     431             :         // Like m_name_id_mapping, but only from names to ids, and includes
     432             :         // item aliases too. Updated by updateAliases()
     433             :         // Note: Not serialized.
     434             : 
     435             :         std::map<std::string, content_t> m_name_id_mapping_with_aliases;
     436             : 
     437             :         // A mapping from groups to a list of content_ts (and their levels)
     438             :         // that belong to it.  Necessary for a direct lookup in getIds().
     439             :         // Note: Not serialized.
     440             :         std::map<std::string, GroupItems> m_group_to_items;
     441             : 
     442             :         // Next possibly free id
     443             :         content_t m_next_id;
     444             : 
     445             :         // NodeResolvers to callback once node registration has ended
     446             :         std::vector<NodeResolver *> m_pending_resolve_callbacks;
     447             : 
     448             :         // True when all nodes have been registered
     449             :         bool m_node_registration_complete;
     450             : };
     451             : 
     452             : 
     453           1 : CNodeDefManager::CNodeDefManager()
     454             : {
     455           1 :         clear();
     456           1 : }
     457             : 
     458             : 
     459           3 : CNodeDefManager::~CNodeDefManager()
     460             : {
     461             : #ifndef SERVER
     462        5196 :         for (u32 i = 0; i < m_content_features.size(); i++) {
     463        5195 :                 ContentFeatures *f = &m_content_features[i];
     464      129875 :                 for (u32 j = 0; j < 24; j++) {
     465      124680 :                         if (f->mesh_ptr[j])
     466      105122 :                                 f->mesh_ptr[j]->drop();
     467             :                 }
     468             :         }
     469             : #endif
     470           2 : }
     471             : 
     472             : 
     473           2 : void CNodeDefManager::clear()
     474             : {
     475           2 :         m_content_features.clear();
     476           2 :         m_name_id_mapping.clear();
     477           2 :         m_name_id_mapping_with_aliases.clear();
     478           2 :         m_group_to_items.clear();
     479           2 :         m_next_id = 0;
     480             : 
     481           2 :         resetNodeResolveState();
     482             : 
     483           2 :         u32 initial_length = 0;
     484           2 :         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
     485           2 :         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
     486           2 :         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
     487           2 :         m_content_features.resize(initial_length);
     488             : 
     489             :         // Set CONTENT_UNKNOWN
     490             :         {
     491           4 :                 ContentFeatures f;
     492           2 :                 f.name = "unknown";
     493             :                 // Insert directly into containers
     494           2 :                 content_t c = CONTENT_UNKNOWN;
     495           2 :                 m_content_features[c] = f;
     496           2 :                 addNameIdMapping(c, f.name);
     497             :         }
     498             : 
     499             :         // Set CONTENT_AIR
     500             :         {
     501           4 :                 ContentFeatures f;
     502           2 :                 f.name                = "air";
     503           2 :                 f.drawtype            = NDT_AIRLIKE;
     504           2 :                 f.param_type          = CPT_LIGHT;
     505           2 :                 f.light_propagates    = true;
     506           2 :                 f.sunlight_propagates = true;
     507           2 :                 f.walkable            = false;
     508           2 :                 f.pointable           = false;
     509           2 :                 f.diggable            = false;
     510           2 :                 f.buildable_to        = true;
     511           2 :                 f.is_ground_content   = true;
     512             :                 // Insert directly into containers
     513           2 :                 content_t c = CONTENT_AIR;
     514           2 :                 m_content_features[c] = f;
     515           2 :                 addNameIdMapping(c, f.name);
     516             :         }
     517             : 
     518             :         // Set CONTENT_IGNORE
     519             :         {
     520           4 :                 ContentFeatures f;
     521           2 :                 f.name                = "ignore";
     522           2 :                 f.drawtype            = NDT_AIRLIKE;
     523           2 :                 f.param_type          = CPT_NONE;
     524           2 :                 f.light_propagates    = false;
     525           2 :                 f.sunlight_propagates = false;
     526           2 :                 f.walkable            = false;
     527           2 :                 f.pointable           = false;
     528           2 :                 f.diggable            = false;
     529           2 :                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
     530           2 :                 f.is_ground_content   = true;
     531             :                 // Insert directly into containers
     532           2 :                 content_t c = CONTENT_IGNORE;
     533           2 :                 m_content_features[c] = f;
     534           2 :                 addNameIdMapping(c, f.name);
     535             :         }
     536           2 : }
     537             : 
     538             : 
     539           0 : IWritableNodeDefManager *CNodeDefManager::clone()
     540             : {
     541           0 :         CNodeDefManager *mgr = new CNodeDefManager();
     542           0 :         *mgr = *this;
     543           0 :         return mgr;
     544             : }
     545             : 
     546             : 
     547    93984264 : inline const ContentFeatures& CNodeDefManager::get(content_t c) const
     548             : {
     549    93984264 :         return c < m_content_features.size()
     550    93969801 :                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
     551             : }
     552             : 
     553             : 
     554    42270016 : inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
     555             : {
     556    42270016 :         return get(n.getContent());
     557             : }
     558             : 
     559             : 
     560       30116 : bool CNodeDefManager::getId(const std::string &name, content_t &result) const
     561             : {
     562             :         std::map<std::string, content_t>::const_iterator
     563       30116 :                 i = m_name_id_mapping_with_aliases.find(name);
     564       30116 :         if(i == m_name_id_mapping_with_aliases.end())
     565          28 :                 return false;
     566       30088 :         result = i->second;
     567       30088 :         return true;
     568             : }
     569             : 
     570             : 
     571       30075 : content_t CNodeDefManager::getId(const std::string &name) const
     572             : {
     573       30075 :         content_t id = CONTENT_IGNORE;
     574       30075 :         getId(name, id);
     575       30075 :         return id;
     576             : }
     577             : 
     578             : 
     579           0 : void CNodeDefManager::getIds(const std::string &name,
     580             :                 std::set<content_t> &result) const
     581             : {
     582             :         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
     583           0 :         if (name.substr(0,6) != "group:") {
     584           0 :                 content_t id = CONTENT_IGNORE;
     585           0 :                 if(getId(name, id))
     586           0 :                         result.insert(id);
     587           0 :                 return;
     588             :         }
     589           0 :         std::string group = name.substr(6);
     590             : 
     591             :         std::map<std::string, GroupItems>::const_iterator
     592           0 :                 i = m_group_to_items.find(group);
     593           0 :         if (i == m_group_to_items.end())
     594           0 :                 return;
     595             : 
     596           0 :         const GroupItems &items = i->second;
     597           0 :         for (GroupItems::const_iterator j = items.begin();
     598           0 :                 j != items.end(); ++j) {
     599           0 :                 if ((*j).second != 0)
     600           0 :                         result.insert((*j).first);
     601             :         }
     602             :         //printf("getIds: %dus\n", t.stop());
     603             : }
     604             : 
     605             : 
     606          41 : const ContentFeatures& CNodeDefManager::get(const std::string &name) const
     607             : {
     608          41 :         content_t id = CONTENT_UNKNOWN;
     609          41 :         getId(name, id);
     610          41 :         return get(id);
     611             : }
     612             : 
     613             : 
     614             : // returns CONTENT_IGNORE if no free ID found
     615           0 : content_t CNodeDefManager::allocateId()
     616             : {
     617           0 :         for (content_t id = m_next_id;
     618           0 :                         id >= m_next_id; // overflow?
     619             :                         ++id) {
     620           0 :                 while (id >= m_content_features.size()) {
     621           0 :                         m_content_features.push_back(ContentFeatures());
     622             :                 }
     623           0 :                 const ContentFeatures &f = m_content_features[id];
     624           0 :                 if (f.name == "") {
     625           0 :                         m_next_id = id + 1;
     626           0 :                         return id;
     627             :                 }
     628             :         }
     629             :         // If we arrive here, an overflow occurred in id.
     630             :         // That means no ID was found
     631           0 :         return CONTENT_IGNORE;
     632             : }
     633             : 
     634             : 
     635             : // IWritableNodeDefManager
     636           0 : content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
     637             : {
     638             :         // Pre-conditions
     639             :         assert(name != "");
     640             :         assert(name == def.name);
     641             : 
     642             :         // Don't allow redefining ignore (but allow air and unknown)
     643           0 :         if (name == "ignore") {
     644             :                 infostream << "NodeDefManager: WARNING: Ignoring "
     645           0 :                         "CONTENT_IGNORE redefinition"<<std::endl;
     646           0 :                 return CONTENT_IGNORE;
     647             :         }
     648             : 
     649           0 :         content_t id = CONTENT_IGNORE;
     650           0 :         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
     651             :                 // Get new id
     652           0 :                 id = allocateId();
     653           0 :                 if (id == CONTENT_IGNORE) {
     654             :                         infostream << "NodeDefManager: WARNING: Absolute "
     655           0 :                                 "limit reached" << std::endl;
     656           0 :                         return CONTENT_IGNORE;
     657             :                 }
     658             :                 assert(id != CONTENT_IGNORE);
     659           0 :                 addNameIdMapping(id, name);
     660             :         }
     661           0 :         m_content_features[id] = def;
     662           0 :         verbosestream << "NodeDefManager: registering content id \"" << id
     663           0 :                 << "\": name=\"" << def.name << "\""<<std::endl;
     664             : 
     665             :         // Add this content to the list of all groups it belongs to
     666             :         // FIXME: This should remove a node from groups it no longer
     667             :         // belongs to when a node is re-registered
     668           0 :         for (ItemGroupList::const_iterator i = def.groups.begin();
     669           0 :                 i != def.groups.end(); ++i) {
     670           0 :                 std::string group_name = i->first;
     671             : 
     672             :                 std::map<std::string, GroupItems>::iterator
     673           0 :                         j = m_group_to_items.find(group_name);
     674           0 :                 if (j == m_group_to_items.end()) {
     675           0 :                         m_group_to_items[group_name].push_back(
     676           0 :                                 std::make_pair(id, i->second));
     677             :                 } else {
     678           0 :                         GroupItems &items = j->second;
     679           0 :                         items.push_back(std::make_pair(id, i->second));
     680             :                 }
     681             :         }
     682           0 :         return id;
     683             : }
     684             : 
     685             : 
     686           0 : content_t CNodeDefManager::allocateDummy(const std::string &name)
     687             : {
     688             :         assert(name != "");   // Pre-condition
     689           0 :         ContentFeatures f;
     690           0 :         f.name = name;
     691           0 :         return set(name, f);
     692             : }
     693             : 
     694             : 
     695           1 : void CNodeDefManager::updateAliases(IItemDefManager *idef)
     696             : {
     697           2 :         std::set<std::string> all = idef->getAll();
     698           1 :         m_name_id_mapping_with_aliases.clear();
     699       22025 :         for (std::set<std::string>::iterator
     700        7343 :                         i = all.begin(); i != all.end(); i++) {
     701       14682 :                 std::string name = *i;
     702       14682 :                 std::string convert_to = idef->getAlias(name);
     703             :                 content_t id;
     704        7341 :                 if (m_name_id_mapping.getId(convert_to, id)) {
     705             :                         m_name_id_mapping_with_aliases.insert(
     706        6940 :                                 std::make_pair(name, id));
     707             :                 }
     708             :         }
     709           1 : }
     710             : 
     711           1 : void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
     712             : {
     713             :         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
     714           1 :                 "overrides to textures from " << override_filepath << std::endl;
     715             : 
     716           2 :         std::ifstream infile(override_filepath.c_str());
     717           2 :         std::string line;
     718           1 :         int line_c = 0;
     719           1 :         while (std::getline(infile, line)) {
     720           0 :                 line_c++;
     721           0 :                 if (trim(line) == "")
     722           0 :                         continue;
     723           0 :                 std::vector<std::string> splitted = str_split(line, ' ');
     724           0 :                 if (splitted.size() != 3) {
     725           0 :                         errorstream << override_filepath
     726           0 :                                 << ":" << line_c << " Could not apply texture override \""
     727           0 :                                 << line << "\": Syntax error" << std::endl;
     728           0 :                         continue;
     729             :                 }
     730             : 
     731             :                 content_t id;
     732           0 :                 if (!getId(splitted[0], id)) {
     733           0 :                         errorstream << override_filepath
     734           0 :                                 << ":" << line_c << " Could not apply texture override \""
     735           0 :                                 << line << "\": Unknown node \""
     736           0 :                                 << splitted[0] << "\"" << std::endl;
     737           0 :                         continue;
     738             :                 }
     739             : 
     740           0 :                 ContentFeatures &nodedef = m_content_features[id];
     741             : 
     742           0 :                 if (splitted[1] == "top")
     743           0 :                         nodedef.tiledef[0].name = splitted[2];
     744           0 :                 else if (splitted[1] == "bottom")
     745           0 :                         nodedef.tiledef[1].name = splitted[2];
     746           0 :                 else if (splitted[1] == "right")
     747           0 :                         nodedef.tiledef[2].name = splitted[2];
     748           0 :                 else if (splitted[1] == "left")
     749           0 :                         nodedef.tiledef[3].name = splitted[2];
     750           0 :                 else if (splitted[1] == "back")
     751           0 :                         nodedef.tiledef[4].name = splitted[2];
     752           0 :                 else if (splitted[1] == "front")
     753           0 :                         nodedef.tiledef[5].name = splitted[2];
     754           0 :                 else if (splitted[1] == "all" || splitted[1] == "*")
     755           0 :                         for (int i = 0; i < 6; i++)
     756           0 :                                 nodedef.tiledef[i].name = splitted[2];
     757           0 :                 else if (splitted[1] == "sides")
     758           0 :                         for (int i = 2; i < 6; i++)
     759           0 :                                 nodedef.tiledef[i].name = splitted[2];
     760             :                 else {
     761           0 :                         errorstream << override_filepath
     762           0 :                                 << ":" << line_c << " Could not apply texture override \""
     763           0 :                                 << line << "\": Unknown node side \""
     764           0 :                                 << splitted[1] << "\"" << std::endl;
     765           0 :                         continue;
     766             :                 }
     767             :         }
     768           1 : }
     769             : 
     770           1 : void CNodeDefManager::updateTextures(IGameDef *gamedef,
     771             :         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
     772             :         void *progress_callback_args)
     773             : {
     774             : #ifndef SERVER
     775             :         infostream << "CNodeDefManager::updateTextures(): Updating "
     776           1 :                 "textures in node definitions" << std::endl;
     777           1 :         ITextureSource *tsrc = gamedef->tsrc();
     778           1 :         IShaderSource *shdsrc = gamedef->getShaderSource();
     779           1 :         scene::ISceneManager* smgr = gamedef->getSceneManager();
     780           1 :         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
     781             : 
     782           1 :         bool new_style_water           = g_settings->getBool("new_style_water");
     783           1 :         bool new_style_leaves          = g_settings->getBool("new_style_leaves");
     784           1 :         bool connected_glass           = g_settings->getBool("connected_glass");
     785           1 :         bool opaque_water              = g_settings->getBool("opaque_water");
     786           1 :         bool enable_shaders            = g_settings->getBool("enable_shaders");
     787           1 :         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
     788           1 :         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
     789           1 :         bool enable_mesh_cache         = g_settings->getBool("enable_mesh_cache");
     790           1 :         bool enable_minimap            = g_settings->getBool("enable_minimap");
     791             : 
     792           2 :         bool use_normal_texture = enable_shaders &&
     793           2 :                 (enable_bumpmapping || enable_parallax_occlusion);
     794             : 
     795           1 :         u32 size = m_content_features.size();
     796             : 
     797        5196 :         for (u32 i = 0; i < size; i++) {
     798        5195 :                 ContentFeatures *f = &m_content_features[i];
     799             : 
     800             :                 // minimap pixel color - the average color of a texture
     801        5195 :                 if (enable_minimap && f->tiledef[0].name != "")
     802        5144 :                         f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
     803             : 
     804             :                 // Figure out the actual tiles to use
     805       10390 :                 TileDef tiledef[6];
     806       36365 :                 for (u32 j = 0; j < 6; j++) {
     807       31170 :                         tiledef[j] = f->tiledef[j];
     808       31170 :                         if (tiledef[j].name == "")
     809         306 :                                 tiledef[j].name = "unknown_node.png";
     810             :                 }
     811             : 
     812        5195 :                 bool is_liquid = false;
     813        5195 :                 bool is_water_surface = false;
     814             : 
     815        5195 :                 u8 material_type = (f->alpha == 255) ?
     816        5195 :                         TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
     817             : 
     818        5195 :                 switch (f->drawtype) {
     819             :                 default:
     820             :                 case NDT_NORMAL:
     821         300 :                         f->solidness = 2;
     822         300 :                         break;
     823             :                 case NDT_AIRLIKE:
     824          19 :                         f->solidness = 0;
     825          19 :                         break;
     826             :                 case NDT_LIQUID:
     827             :                         assert(f->liquid_type == LIQUID_SOURCE);
     828           2 :                         if (opaque_water)
     829           0 :                                 f->alpha = 255;
     830           2 :                         if (new_style_water){
     831           0 :                                 f->solidness = 0;
     832             :                         } else {
     833           2 :                                 f->solidness = 1;
     834           2 :                                 f->backface_culling = false;
     835             :                         }
     836           2 :                         is_liquid = true;
     837           2 :                         break;
     838             :                 case NDT_FLOWINGLIQUID:
     839             :                         assert(f->liquid_type == LIQUID_FLOWING);
     840           2 :                         f->solidness = 0;
     841           2 :                         if (opaque_water)
     842           0 :                                 f->alpha = 255;
     843           2 :                         is_liquid = true;
     844           2 :                         break;
     845             :                 case NDT_GLASSLIKE:
     846           4 :                         f->solidness = 0;
     847           4 :                         f->visual_solidness = 1;
     848           4 :                         break;
     849             :                 case NDT_GLASSLIKE_FRAMED:
     850           1 :                         f->solidness = 0;
     851           1 :                         f->visual_solidness = 1;
     852           1 :                         break;
     853             :                 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
     854           9 :                         f->solidness = 0;
     855           9 :                         f->visual_solidness = 1;
     856           9 :                         f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
     857           9 :                         break;
     858             :                 case NDT_ALLFACES:
     859           0 :                         f->solidness = 0;
     860           0 :                         f->visual_solidness = 1;
     861           0 :                         break;
     862             :                 case NDT_ALLFACES_OPTIONAL:
     863          22 :                         if (new_style_leaves) {
     864          22 :                                 f->drawtype = NDT_ALLFACES;
     865          22 :                                 f->solidness = 0;
     866          22 :                                 f->visual_solidness = 1;
     867             :                         } else {
     868           0 :                                 f->drawtype = NDT_NORMAL;
     869           0 :                                 f->solidness = 2;
     870           0 :                                 for (u32 i = 0; i < 6; i++)
     871           0 :                                         tiledef[i].name += std::string("^[noalpha");
     872             :                         }
     873          22 :                         if (f->waving == 1)
     874          20 :                                 material_type = TILE_MATERIAL_WAVING_LEAVES;
     875          22 :                         break;
     876             :                 case NDT_PLANTLIKE:
     877         145 :                         f->solidness = 0;
     878         145 :                         f->backface_culling = false;
     879         145 :                         if (f->waving == 1)
     880          45 :                                 material_type = TILE_MATERIAL_WAVING_PLANTS;
     881         145 :                         break;
     882             :                 case NDT_FIRELIKE:
     883           0 :                         f->backface_culling = false;
     884           0 :                         f->solidness = 0;
     885           0 :                         break;
     886             :                 case NDT_MESH:
     887        1403 :                         f->solidness = 0;
     888        1403 :                         f->backface_culling = false;
     889        1403 :                         break;
     890             :                 case NDT_TORCHLIKE:
     891             :                 case NDT_SIGNLIKE:
     892             :                 case NDT_FENCELIKE:
     893             :                 case NDT_RAILLIKE:
     894             :                 case NDT_NODEBOX:
     895        3288 :                         f->solidness = 0;
     896        3288 :                         break;
     897             :                 }
     898             : 
     899        5195 :                 if (is_liquid) {
     900           4 :                         material_type = (f->alpha == 255) ?
     901           4 :                                 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
     902           4 :                         if (f->name == "default:water_source")
     903           1 :                                 is_water_surface = true;
     904             :                 }
     905             : 
     906             :                 u32 tile_shader[6];
     907       36365 :                 for (u16 j = 0; j < 6; j++) {
     908       93510 :                         tile_shader[j] = shdsrc->getShader("nodes_shader",
     909       62340 :                                 material_type, f->drawtype);
     910             :                 }
     911             : 
     912        5195 :                 if (is_water_surface) {
     913           2 :                         tile_shader[0] = shdsrc->getShader("water_surface_shader",
     914           2 :                                 material_type, f->drawtype);
     915             :                 }
     916             : 
     917             :                 // Tiles (fill in f->tiles[])
     918       36365 :                 for (u16 j = 0; j < 6; j++) {
     919       93510 :                         fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
     920       93510 :                                 use_normal_texture, f->backface_culling, f->alpha, material_type);
     921             :                 }
     922             : 
     923             :                 // Special tiles (fill in f->special_tiles[])
     924       36365 :                 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
     925       93510 :                         fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
     926             :                                 tile_shader[j], use_normal_texture,
     927       93510 :                                 f->tiledef_special[j].backface_culling, f->alpha, material_type);
     928             :                 }
     929             : 
     930        5195 :                 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
     931             :                         // Meshnode drawtype
     932             :                         // Read the mesh and apply scale
     933        1403 :                         f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
     934        1403 :                         if (f->mesh_ptr[0]){
     935        1403 :                                 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
     936        1403 :                                 scaleMesh(f->mesh_ptr[0], scale);
     937        1403 :                                 recalculateBoundingBox(f->mesh_ptr[0]);
     938        1403 :                                 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
     939             :                         }
     940       10820 :                 } else if ((f->drawtype == NDT_NODEBOX) &&
     941        6472 :                                 ((f->node_box.type == NODEBOX_REGULAR) ||
     942       10257 :                                 (f->node_box.type == NODEBOX_FIXED)) &&
     943        3229 :                                 (!f->node_box.fixed.empty())) {
     944             :                         //Convert regular nodebox nodes to meshnodes
     945             :                         //Change the drawtype and apply scale
     946        3229 :                         f->drawtype = NDT_MESH;
     947        3229 :                         f->mesh_ptr[0] = convertNodeboxNodeToMesh(f);
     948        3229 :                         v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
     949        3229 :                         scaleMesh(f->mesh_ptr[0], scale);
     950        3229 :                         recalculateBoundingBox(f->mesh_ptr[0]);
     951        3229 :                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
     952             :                 }
     953             : 
     954             :                 //Cache 6dfacedir and wallmounted rotated clones of meshes
     955        5195 :                 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
     956      104760 :                         for (u16 j = 1; j < 24; j++) {
     957      100395 :                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
     958      100395 :                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
     959      100395 :                                 recalculateBoundingBox(f->mesh_ptr[j]);
     960      100395 :                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
     961        4365 :                         }
     962         830 :                 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
     963             :                         static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
     964         114 :                         for (u16 j = 1; j < 6; j++) {
     965          95 :                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
     966          95 :                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
     967          95 :                                 recalculateBoundingBox(f->mesh_ptr[j]);
     968          95 :                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
     969             :                         }
     970          19 :                         rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
     971          19 :                         recalculateBoundingBox(f->mesh_ptr[0]);
     972          19 :                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
     973             :                 }
     974             : 
     975        5195 :                 progress_callback(progress_callback_args, i, size);
     976             :         }
     977             : #endif
     978           1 : }
     979             : 
     980             : 
     981             : #ifndef SERVER
     982       62340 : void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
     983             :                 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
     984             :                 bool backface_culling, u8 alpha, u8 material_type)
     985             : {
     986       62340 :         tile->shader_id     = shader_id;
     987       62340 :         tile->texture       = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
     988       62340 :         tile->alpha         = alpha;
     989       62340 :         tile->material_type = material_type;
     990             : 
     991             :         // Normal texture
     992       62340 :         if (use_normal_texture)
     993       62340 :                 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
     994             : 
     995             :         // Material flags
     996       62340 :         tile->material_flags = 0;
     997       62340 :         if (backface_culling)
     998       53036 :                 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
     999       62340 :         if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
    1000          58 :                 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
    1001             : 
    1002             :         // Animation parameters
    1003       62340 :         int frame_count = 1;
    1004       62340 :         if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
    1005             :                 // Get texture size to determine frame count by aspect ratio
    1006          58 :                 v2u32 size = tile->texture->getOriginalSize();
    1007         116 :                 int frame_height = (float)size.X /
    1008         116 :                                 (float)tiledef->animation.aspect_w *
    1009         116 :                                 (float)tiledef->animation.aspect_h;
    1010          58 :                 frame_count = size.Y / frame_height;
    1011          58 :                 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
    1012          58 :                 tile->animation_frame_count = frame_count;
    1013          58 :                 tile->animation_frame_length_ms = frame_length_ms;
    1014             :         }
    1015             : 
    1016       62340 :         if (frame_count == 1) {
    1017       62284 :                 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
    1018             :         } else {
    1019         112 :                 std::ostringstream os(std::ios::binary);
    1020          56 :                 tile->frames.resize(frame_count);
    1021             : 
    1022         863 :                 for (int i = 0; i < frame_count; i++) {
    1023             : 
    1024         807 :                         FrameSpec frame;
    1025             : 
    1026         807 :                         os.str("");
    1027         807 :                         os << tiledef->name << "^[verticalframe:"
    1028         807 :                                 << frame_count << ":" << i;
    1029             : 
    1030         807 :                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
    1031         807 :                         if (tile->normal_texture)
    1032           0 :                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
    1033         807 :                         tile->frames[i] = frame;
    1034             :                 }
    1035             :         }
    1036       62340 : }
    1037             : #endif
    1038             : 
    1039             : 
    1040           0 : void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
    1041             : {
    1042           0 :         writeU8(os, 1); // version
    1043           0 :         u16 count = 0;
    1044           0 :         std::ostringstream os2(std::ios::binary);
    1045           0 :         for (u32 i = 0; i < m_content_features.size(); i++) {
    1046           0 :                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
    1047           0 :                                 || i == CONTENT_UNKNOWN)
    1048           0 :                         continue;
    1049           0 :                 const ContentFeatures *f = &m_content_features[i];
    1050           0 :                 if (f->name == "")
    1051           0 :                         continue;
    1052           0 :                 writeU16(os2, i);
    1053             :                 // Wrap it in a string to allow different lengths without
    1054             :                 // strict version incompatibilities
    1055           0 :                 std::ostringstream wrapper_os(std::ios::binary);
    1056           0 :                 f->serialize(wrapper_os, protocol_version);
    1057           0 :                 os2<<serializeString(wrapper_os.str());
    1058             : 
    1059             :                 // must not overflow
    1060           0 :                 u16 next = count + 1;
    1061           0 :                 FATAL_ERROR_IF(next < count, "Overflow");
    1062           0 :                 count++;
    1063             :         }
    1064           0 :         writeU16(os, count);
    1065           0 :         os << serializeLongString(os2.str());
    1066           0 : }
    1067             : 
    1068             : 
    1069           1 : void CNodeDefManager::deSerialize(std::istream &is)
    1070             : {
    1071           1 :         clear();
    1072           1 :         int version = readU8(is);
    1073           1 :         if (version != 1)
    1074           0 :                 throw SerializationError("unsupported NodeDefinitionManager version");
    1075           1 :         u16 count = readU16(is);
    1076           2 :         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
    1077           2 :         ContentFeatures f;
    1078        5193 :         for (u16 n = 0; n < count; n++) {
    1079        5192 :                 u16 i = readU16(is2);
    1080             : 
    1081             :                 // Read it from the string wrapper
    1082       10384 :                 std::string wrapper = deSerializeString(is2);
    1083       10384 :                 std::istringstream wrapper_is(wrapper, std::ios::binary);
    1084        5192 :                 f.deSerialize(wrapper_is);
    1085             : 
    1086             :                 // Check error conditions
    1087        5192 :                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
    1088             :                         infostream << "NodeDefManager::deSerialize(): WARNING: "
    1089           0 :                                 "not changing builtin node " << i << std::endl;
    1090           0 :                         continue;
    1091             :                 }
    1092        5192 :                 if (f.name == "") {
    1093             :                         infostream << "NodeDefManager::deSerialize(): WARNING: "
    1094           0 :                                 "received empty name" << std::endl;
    1095           0 :                         continue;
    1096             :                 }
    1097             : 
    1098             :                 // Ignore aliases
    1099             :                 u16 existing_id;
    1100        5192 :                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
    1101             :                         infostream << "NodeDefManager::deSerialize(): WARNING: "
    1102           0 :                                 "already defined with different ID: " << f.name << std::endl;
    1103           0 :                         continue;
    1104             :                 }
    1105             : 
    1106             :                 // All is ok, add node definition with the requested ID
    1107        5192 :                 if (i >= m_content_features.size())
    1108        5067 :                         m_content_features.resize((u32)(i) + 1);
    1109        5192 :                 m_content_features[i] = f;
    1110        5192 :                 addNameIdMapping(i, f.name);
    1111        5192 :                 verbosestream << "deserialized " << f.name << std::endl;
    1112             :         }
    1113           1 : }
    1114             : 
    1115             : 
    1116        5198 : void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
    1117             : {
    1118        5198 :         m_name_id_mapping.set(i, name);
    1119        5198 :         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
    1120        5198 : }
    1121             : 
    1122             : 
    1123           1 : IWritableNodeDefManager *createNodeDefManager()
    1124             : {
    1125           1 :         return new CNodeDefManager();
    1126             : }
    1127             : 
    1128             : 
    1129             : //// Serialization of old ContentFeatures formats
    1130           0 : void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
    1131             : {
    1132           0 :         if (protocol_version == 13)
    1133             :         {
    1134           0 :                 writeU8(os, 5); // version
    1135           0 :                 os<<serializeString(name);
    1136           0 :                 writeU16(os, groups.size());
    1137           0 :                 for (ItemGroupList::const_iterator
    1138           0 :                                 i = groups.begin(); i != groups.end(); i++) {
    1139           0 :                         os<<serializeString(i->first);
    1140           0 :                         writeS16(os, i->second);
    1141             :                 }
    1142           0 :                 writeU8(os, drawtype);
    1143           0 :                 writeF1000(os, visual_scale);
    1144           0 :                 writeU8(os, 6);
    1145           0 :                 for (u32 i = 0; i < 6; i++)
    1146           0 :                         tiledef[i].serialize(os, protocol_version);
    1147             :                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
    1148           0 :                 writeU8(os, 2);
    1149           0 :                 for (u32 i = 0; i < 2; i++)
    1150           0 :                         tiledef_special[i].serialize(os, protocol_version);
    1151           0 :                 writeU8(os, alpha);
    1152           0 :                 writeU8(os, post_effect_color.getAlpha());
    1153           0 :                 writeU8(os, post_effect_color.getRed());
    1154           0 :                 writeU8(os, post_effect_color.getGreen());
    1155           0 :                 writeU8(os, post_effect_color.getBlue());
    1156           0 :                 writeU8(os, param_type);
    1157           0 :                 writeU8(os, param_type_2);
    1158           0 :                 writeU8(os, is_ground_content);
    1159           0 :                 writeU8(os, light_propagates);
    1160           0 :                 writeU8(os, sunlight_propagates);
    1161           0 :                 writeU8(os, walkable);
    1162           0 :                 writeU8(os, pointable);
    1163           0 :                 writeU8(os, diggable);
    1164           0 :                 writeU8(os, climbable);
    1165           0 :                 writeU8(os, buildable_to);
    1166           0 :                 os<<serializeString(""); // legacy: used to be metadata_name
    1167           0 :                 writeU8(os, liquid_type);
    1168           0 :                 os<<serializeString(liquid_alternative_flowing);
    1169           0 :                 os<<serializeString(liquid_alternative_source);
    1170           0 :                 writeU8(os, liquid_viscosity);
    1171           0 :                 writeU8(os, light_source);
    1172           0 :                 writeU32(os, damage_per_second);
    1173           0 :                 node_box.serialize(os, protocol_version);
    1174           0 :                 selection_box.serialize(os, protocol_version);
    1175           0 :                 writeU8(os, legacy_facedir_simple);
    1176           0 :                 writeU8(os, legacy_wallmounted);
    1177           0 :                 serializeSimpleSoundSpec(sound_footstep, os);
    1178           0 :                 serializeSimpleSoundSpec(sound_dig, os);
    1179           0 :                 serializeSimpleSoundSpec(sound_dug, os);
    1180             :         }
    1181           0 :         else if (protocol_version > 13 && protocol_version < 24) {
    1182           0 :                 writeU8(os, 6); // version
    1183           0 :                 os<<serializeString(name);
    1184           0 :                 writeU16(os, groups.size());
    1185           0 :                 for (ItemGroupList::const_iterator
    1186           0 :                         i = groups.begin(); i != groups.end(); i++) {
    1187           0 :                                 os<<serializeString(i->first);
    1188           0 :                                 writeS16(os, i->second);
    1189             :                 }
    1190           0 :                 writeU8(os, drawtype);
    1191           0 :                 writeF1000(os, visual_scale);
    1192           0 :                 writeU8(os, 6);
    1193           0 :                 for (u32 i = 0; i < 6; i++)
    1194           0 :                         tiledef[i].serialize(os, protocol_version);
    1195             :                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
    1196           0 :                 writeU8(os, 2);
    1197           0 :                 for (u32 i = 0; i < 2; i++)
    1198           0 :                         tiledef_special[i].serialize(os, protocol_version);
    1199           0 :                 writeU8(os, alpha);
    1200           0 :                 writeU8(os, post_effect_color.getAlpha());
    1201           0 :                 writeU8(os, post_effect_color.getRed());
    1202           0 :                 writeU8(os, post_effect_color.getGreen());
    1203           0 :                 writeU8(os, post_effect_color.getBlue());
    1204           0 :                 writeU8(os, param_type);
    1205           0 :                 writeU8(os, param_type_2);
    1206           0 :                 writeU8(os, is_ground_content);
    1207           0 :                 writeU8(os, light_propagates);
    1208           0 :                 writeU8(os, sunlight_propagates);
    1209           0 :                 writeU8(os, walkable);
    1210           0 :                 writeU8(os, pointable);
    1211           0 :                 writeU8(os, diggable);
    1212           0 :                 writeU8(os, climbable);
    1213           0 :                 writeU8(os, buildable_to);
    1214           0 :                 os<<serializeString(""); // legacy: used to be metadata_name
    1215           0 :                 writeU8(os, liquid_type);
    1216           0 :                 os<<serializeString(liquid_alternative_flowing);
    1217           0 :                 os<<serializeString(liquid_alternative_source);
    1218           0 :                 writeU8(os, liquid_viscosity);
    1219           0 :                 writeU8(os, liquid_renewable);
    1220           0 :                 writeU8(os, light_source);
    1221           0 :                 writeU32(os, damage_per_second);
    1222           0 :                 node_box.serialize(os, protocol_version);
    1223           0 :                 selection_box.serialize(os, protocol_version);
    1224           0 :                 writeU8(os, legacy_facedir_simple);
    1225           0 :                 writeU8(os, legacy_wallmounted);
    1226           0 :                 serializeSimpleSoundSpec(sound_footstep, os);
    1227           0 :                 serializeSimpleSoundSpec(sound_dig, os);
    1228           0 :                 serializeSimpleSoundSpec(sound_dug, os);
    1229           0 :                 writeU8(os, rightclickable);
    1230           0 :                 writeU8(os, drowning);
    1231           0 :                 writeU8(os, leveled);
    1232           0 :                 writeU8(os, liquid_range);
    1233             :         } else
    1234             :                 throw SerializationError("ContentFeatures::serialize(): "
    1235           0 :                         "Unsupported version requested");
    1236           0 : }
    1237             : 
    1238             : 
    1239           0 : void ContentFeatures::deSerializeOld(std::istream &is, int version)
    1240             : {
    1241           0 :         if (version == 5) // In PROTOCOL_VERSION 13
    1242             :         {
    1243           0 :                 name = deSerializeString(is);
    1244           0 :                 groups.clear();
    1245           0 :                 u32 groups_size = readU16(is);
    1246           0 :                 for(u32 i=0; i<groups_size; i++){
    1247           0 :                         std::string name = deSerializeString(is);
    1248           0 :                         int value = readS16(is);
    1249           0 :                         groups[name] = value;
    1250             :                 }
    1251           0 :                 drawtype = (enum NodeDrawType)readU8(is);
    1252           0 :                 visual_scale = readF1000(is);
    1253           0 :                 if (readU8(is) != 6)
    1254           0 :                         throw SerializationError("unsupported tile count");
    1255           0 :                 for (u32 i = 0; i < 6; i++)
    1256           0 :                         tiledef[i].deSerialize(is);
    1257           0 :                 if (readU8(is) != CF_SPECIAL_COUNT)
    1258           0 :                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
    1259           0 :                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
    1260           0 :                         tiledef_special[i].deSerialize(is);
    1261           0 :                 alpha = readU8(is);
    1262           0 :                 post_effect_color.setAlpha(readU8(is));
    1263           0 :                 post_effect_color.setRed(readU8(is));
    1264           0 :                 post_effect_color.setGreen(readU8(is));
    1265           0 :                 post_effect_color.setBlue(readU8(is));
    1266           0 :                 param_type = (enum ContentParamType)readU8(is);
    1267           0 :                 param_type_2 = (enum ContentParamType2)readU8(is);
    1268           0 :                 is_ground_content = readU8(is);
    1269           0 :                 light_propagates = readU8(is);
    1270           0 :                 sunlight_propagates = readU8(is);
    1271           0 :                 walkable = readU8(is);
    1272           0 :                 pointable = readU8(is);
    1273           0 :                 diggable = readU8(is);
    1274           0 :                 climbable = readU8(is);
    1275           0 :                 buildable_to = readU8(is);
    1276           0 :                 deSerializeString(is); // legacy: used to be metadata_name
    1277           0 :                 liquid_type = (enum LiquidType)readU8(is);
    1278           0 :                 liquid_alternative_flowing = deSerializeString(is);
    1279           0 :                 liquid_alternative_source = deSerializeString(is);
    1280           0 :                 liquid_viscosity = readU8(is);
    1281           0 :                 light_source = readU8(is);
    1282           0 :                 damage_per_second = readU32(is);
    1283           0 :                 node_box.deSerialize(is);
    1284           0 :                 selection_box.deSerialize(is);
    1285           0 :                 legacy_facedir_simple = readU8(is);
    1286           0 :                 legacy_wallmounted = readU8(is);
    1287           0 :                 deSerializeSimpleSoundSpec(sound_footstep, is);
    1288           0 :                 deSerializeSimpleSoundSpec(sound_dig, is);
    1289           0 :                 deSerializeSimpleSoundSpec(sound_dug, is);
    1290           0 :         } else if (version == 6) {
    1291           0 :                 name = deSerializeString(is);
    1292           0 :                 groups.clear();
    1293           0 :                 u32 groups_size = readU16(is);
    1294           0 :                 for (u32 i = 0; i < groups_size; i++) {
    1295           0 :                         std::string name = deSerializeString(is);
    1296           0 :                         int     value = readS16(is);
    1297           0 :                         groups[name] = value;
    1298             :                 }
    1299           0 :                 drawtype = (enum NodeDrawType)readU8(is);
    1300           0 :                 visual_scale = readF1000(is);
    1301           0 :                 if (readU8(is) != 6)
    1302           0 :                         throw SerializationError("unsupported tile count");
    1303           0 :                 for (u32 i = 0; i < 6; i++)
    1304           0 :                         tiledef[i].deSerialize(is);
    1305             :                 // CF_SPECIAL_COUNT in version 6 = 2
    1306           0 :                 if (readU8(is) != 2)
    1307           0 :                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
    1308           0 :                 for (u32 i = 0; i < 2; i++)
    1309           0 :                         tiledef_special[i].deSerialize(is);
    1310           0 :                 alpha = readU8(is);
    1311           0 :                 post_effect_color.setAlpha(readU8(is));
    1312           0 :                 post_effect_color.setRed(readU8(is));
    1313           0 :                 post_effect_color.setGreen(readU8(is));
    1314           0 :                 post_effect_color.setBlue(readU8(is));
    1315           0 :                 param_type = (enum ContentParamType)readU8(is);
    1316           0 :                 param_type_2 = (enum ContentParamType2)readU8(is);
    1317           0 :                 is_ground_content = readU8(is);
    1318           0 :                 light_propagates = readU8(is);
    1319           0 :                 sunlight_propagates = readU8(is);
    1320           0 :                 walkable = readU8(is);
    1321           0 :                 pointable = readU8(is);
    1322           0 :                 diggable = readU8(is);
    1323           0 :                 climbable = readU8(is);
    1324           0 :                 buildable_to = readU8(is);
    1325           0 :                 deSerializeString(is); // legacy: used to be metadata_name
    1326           0 :                 liquid_type = (enum LiquidType)readU8(is);
    1327           0 :                 liquid_alternative_flowing = deSerializeString(is);
    1328           0 :                 liquid_alternative_source = deSerializeString(is);
    1329           0 :                 liquid_viscosity = readU8(is);
    1330           0 :                 liquid_renewable = readU8(is);
    1331           0 :                 light_source = readU8(is);
    1332           0 :                 damage_per_second = readU32(is);
    1333           0 :                 node_box.deSerialize(is);
    1334           0 :                 selection_box.deSerialize(is);
    1335           0 :                 legacy_facedir_simple = readU8(is);
    1336           0 :                 legacy_wallmounted = readU8(is);
    1337           0 :                 deSerializeSimpleSoundSpec(sound_footstep, is);
    1338           0 :                 deSerializeSimpleSoundSpec(sound_dig, is);
    1339           0 :                 deSerializeSimpleSoundSpec(sound_dug, is);
    1340           0 :                 rightclickable = readU8(is);
    1341           0 :                 drowning = readU8(is);
    1342           0 :                 leveled = readU8(is);
    1343           0 :                 liquid_range = readU8(is);
    1344             :         } else {
    1345           0 :                 throw SerializationError("unsupported ContentFeatures version");
    1346             :         }
    1347           0 : }
    1348             : 
    1349             : 
    1350           0 : inline bool CNodeDefManager::getNodeRegistrationStatus() const
    1351             : {
    1352           0 :         return m_node_registration_complete;
    1353             : }
    1354             : 
    1355             : 
    1356           1 : inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
    1357             : {
    1358           1 :         m_node_registration_complete = completed;
    1359           1 : }
    1360             : 
    1361             : 
    1362           0 : void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
    1363             : {
    1364           0 :         nr->m_ndef = this;
    1365           0 :         if (m_node_registration_complete)
    1366           0 :                 nr->nodeResolveInternal();
    1367             :         else
    1368           0 :                 m_pending_resolve_callbacks.push_back(nr);
    1369           0 : }
    1370             : 
    1371             : 
    1372           0 : bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
    1373             : {
    1374           0 :         size_t len = m_pending_resolve_callbacks.size();
    1375           0 :         for (size_t i = 0; i != len; i++) {
    1376           0 :                 if (nr != m_pending_resolve_callbacks[i])
    1377           0 :                         continue;
    1378             : 
    1379           0 :                 len--;
    1380           0 :                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
    1381           0 :                 m_pending_resolve_callbacks.resize(len);
    1382           0 :                 return true;
    1383             :         }
    1384             : 
    1385           0 :         return false;
    1386             : }
    1387             : 
    1388             : 
    1389           1 : void CNodeDefManager::runNodeResolveCallbacks()
    1390             : {
    1391           1 :         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
    1392           0 :                 NodeResolver *nr = m_pending_resolve_callbacks[i];
    1393           0 :                 nr->nodeResolveInternal();
    1394             :         }
    1395             : 
    1396           1 :         m_pending_resolve_callbacks.clear();
    1397           1 : }
    1398             : 
    1399             : 
    1400           2 : void CNodeDefManager::resetNodeResolveState()
    1401             : {
    1402           2 :         m_node_registration_complete = false;
    1403           2 :         m_pending_resolve_callbacks.clear();
    1404           2 : }
    1405             : 
    1406             : 
    1407             : ////
    1408             : //// NodeResolver
    1409             : ////
    1410             : 
    1411           0 : NodeResolver::NodeResolver()
    1412             : {
    1413           0 :         m_ndef            = NULL;
    1414           0 :         m_nodenames_idx   = 0;
    1415           0 :         m_nnlistsizes_idx = 0;
    1416           0 :         m_resolve_done    = false;
    1417             : 
    1418           0 :         m_nodenames.reserve(16);
    1419           0 :         m_nnlistsizes.reserve(4);
    1420           0 : }
    1421             : 
    1422             : 
    1423           0 : NodeResolver::~NodeResolver()
    1424             : {
    1425           0 :         if (!m_resolve_done && m_ndef)
    1426           0 :                 m_ndef->cancelNodeResolveCallback(this);
    1427           0 : }
    1428             : 
    1429             : 
    1430           0 : void NodeResolver::nodeResolveInternal()
    1431             : {
    1432           0 :         m_nodenames_idx   = 0;
    1433           0 :         m_nnlistsizes_idx = 0;
    1434             : 
    1435           0 :         resolveNodeNames();
    1436           0 :         m_resolve_done = true;
    1437             : 
    1438           0 :         m_nodenames.clear();
    1439           0 :         m_nnlistsizes.clear();
    1440           0 : }
    1441             : 
    1442             : 
    1443           0 : bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
    1444             :         const std::string &node_alt, content_t c_fallback)
    1445             : {
    1446           0 :         if (m_nodenames_idx == m_nodenames.size()) {
    1447           0 :                 *result_out = c_fallback;
    1448           0 :                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
    1449           0 :                 return false;
    1450             :         }
    1451             : 
    1452             :         content_t c;
    1453           0 :         std::string name = m_nodenames[m_nodenames_idx++];
    1454             : 
    1455           0 :         bool success = m_ndef->getId(name, c);
    1456           0 :         if (!success && node_alt != "") {
    1457           0 :                 name = node_alt;
    1458           0 :                 success = m_ndef->getId(name, c);
    1459             :         }
    1460             : 
    1461           0 :         if (!success) {
    1462           0 :                 errorstream << "NodeResolver: failed to resolve node name '" << name
    1463           0 :                         << "'." << std::endl;
    1464           0 :                 c = c_fallback;
    1465             :         }
    1466             : 
    1467           0 :         *result_out = c;
    1468           0 :         return success;
    1469             : }
    1470             : 
    1471             : 
    1472           0 : bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
    1473             :         bool all_required, content_t c_fallback)
    1474             : {
    1475           0 :         bool success = true;
    1476             : 
    1477           0 :         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
    1478           0 :                 errorstream << "NodeResolver: no more node lists" << std::endl;
    1479           0 :                 return false;
    1480             :         }
    1481             : 
    1482           0 :         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
    1483             : 
    1484           0 :         while (length--) {
    1485           0 :                 if (m_nodenames_idx == m_nodenames.size()) {
    1486           0 :                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
    1487           0 :                         return false;
    1488             :                 }
    1489             : 
    1490             :                 content_t c;
    1491           0 :                 std::string &name = m_nodenames[m_nodenames_idx++];
    1492             : 
    1493           0 :                 if (name.substr(0,6) != "group:") {
    1494           0 :                         if (m_ndef->getId(name, c)) {
    1495           0 :                                 result_out->push_back(c);
    1496           0 :                         } else if (all_required) {
    1497           0 :                                 errorstream << "NodeResolver: failed to resolve node name '"
    1498           0 :                                         << name << "'." << std::endl;
    1499           0 :                                 result_out->push_back(c_fallback);
    1500           0 :                                 success = false;
    1501             :                         }
    1502             :                 } else {
    1503           0 :                         std::set<content_t> cids;
    1504           0 :                         std::set<content_t>::iterator it;
    1505           0 :                         m_ndef->getIds(name, cids);
    1506           0 :                         for (it = cids.begin(); it != cids.end(); ++it)
    1507           0 :                                 result_out->push_back(*it);
    1508             :                 }
    1509             :         }
    1510             : 
    1511           0 :         return success;
    1512           3 : }

Generated by: LCOV version 1.11