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