]> git.lizzy.rs Git - dragonfireclient.git/blob - src/nodedef.cpp
Remove new_style_water
[dragonfireclient.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 void 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 void 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                 if(getId(name, id))
613                         result.insert(id);
614                 return;
615         }
616         std::string group = name.substr(6);
617
618         std::map<std::string, GroupItems>::const_iterator
619                 i = m_group_to_items.find(group);
620         if (i == m_group_to_items.end())
621                 return;
622
623         const GroupItems &items = i->second;
624         for (GroupItems::const_iterator j = items.begin();
625                 j != items.end(); ++j) {
626                 if ((*j).second != 0)
627                         result.insert((*j).first);
628         }
629         //printf("getIds: %dus\n", t.stop());
630 }
631
632
633 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
634 {
635         content_t id = CONTENT_UNKNOWN;
636         getId(name, id);
637         return get(id);
638 }
639
640
641 // returns CONTENT_IGNORE if no free ID found
642 content_t CNodeDefManager::allocateId()
643 {
644         for (content_t id = m_next_id;
645                         id >= m_next_id; // overflow?
646                         ++id) {
647                 while (id >= m_content_features.size()) {
648                         m_content_features.push_back(ContentFeatures());
649                 }
650                 const ContentFeatures &f = m_content_features[id];
651                 if (f.name == "") {
652                         m_next_id = id + 1;
653                         return id;
654                 }
655         }
656         // If we arrive here, an overflow occurred in id.
657         // That means no ID was found
658         return CONTENT_IGNORE;
659 }
660
661
662 // IWritableNodeDefManager
663 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
664 {
665         // Pre-conditions
666         assert(name != "");
667         assert(name == def.name);
668
669         // Don't allow redefining ignore (but allow air and unknown)
670         if (name == "ignore") {
671                 warningstream << "NodeDefManager: Ignoring "
672                         "CONTENT_IGNORE redefinition"<<std::endl;
673                 return CONTENT_IGNORE;
674         }
675
676         content_t id = CONTENT_IGNORE;
677         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
678                 // Get new id
679                 id = allocateId();
680                 if (id == CONTENT_IGNORE) {
681                         warningstream << "NodeDefManager: Absolute "
682                                 "limit reached" << std::endl;
683                         return CONTENT_IGNORE;
684                 }
685                 assert(id != CONTENT_IGNORE);
686                 addNameIdMapping(id, name);
687         }
688         m_content_features[id] = def;
689         verbosestream << "NodeDefManager: registering content id \"" << id
690                 << "\": name=\"" << def.name << "\""<<std::endl;
691
692         // Add this content to the list of all groups it belongs to
693         // FIXME: This should remove a node from groups it no longer
694         // belongs to when a node is re-registered
695         for (ItemGroupList::const_iterator i = def.groups.begin();
696                 i != def.groups.end(); ++i) {
697                 std::string group_name = i->first;
698
699                 std::map<std::string, GroupItems>::iterator
700                         j = m_group_to_items.find(group_name);
701                 if (j == m_group_to_items.end()) {
702                         m_group_to_items[group_name].push_back(
703                                 std::make_pair(id, i->second));
704                 } else {
705                         GroupItems &items = j->second;
706                         items.push_back(std::make_pair(id, i->second));
707                 }
708         }
709         return id;
710 }
711
712
713 content_t CNodeDefManager::allocateDummy(const std::string &name)
714 {
715         assert(name != "");     // Pre-condition
716         ContentFeatures f;
717         f.name = name;
718         return set(name, f);
719 }
720
721
722 void CNodeDefManager::updateAliases(IItemDefManager *idef)
723 {
724         std::set<std::string> all = idef->getAll();
725         m_name_id_mapping_with_aliases.clear();
726         for (std::set<std::string>::iterator
727                         i = all.begin(); i != all.end(); ++i) {
728                 std::string name = *i;
729                 std::string convert_to = idef->getAlias(name);
730                 content_t id;
731                 if (m_name_id_mapping.getId(convert_to, id)) {
732                         m_name_id_mapping_with_aliases.insert(
733                                 std::make_pair(name, id));
734                 }
735         }
736 }
737
738 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
739 {
740         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
741                 "overrides to textures from " << override_filepath << std::endl;
742
743         std::ifstream infile(override_filepath.c_str());
744         std::string line;
745         int line_c = 0;
746         while (std::getline(infile, line)) {
747                 line_c++;
748                 if (trim(line) == "")
749                         continue;
750                 std::vector<std::string> splitted = str_split(line, ' ');
751                 if (splitted.size() != 3) {
752                         errorstream << override_filepath
753                                 << ":" << line_c << " Could not apply texture override \""
754                                 << line << "\": Syntax error" << std::endl;
755                         continue;
756                 }
757
758                 content_t id;
759                 if (!getId(splitted[0], id)) {
760                         errorstream << override_filepath
761                                 << ":" << line_c << " Could not apply texture override \""
762                                 << line << "\": Unknown node \""
763                                 << splitted[0] << "\"" << std::endl;
764                         continue;
765                 }
766
767                 ContentFeatures &nodedef = m_content_features[id];
768
769                 if (splitted[1] == "top")
770                         nodedef.tiledef[0].name = splitted[2];
771                 else if (splitted[1] == "bottom")
772                         nodedef.tiledef[1].name = splitted[2];
773                 else if (splitted[1] == "right")
774                         nodedef.tiledef[2].name = splitted[2];
775                 else if (splitted[1] == "left")
776                         nodedef.tiledef[3].name = splitted[2];
777                 else if (splitted[1] == "back")
778                         nodedef.tiledef[4].name = splitted[2];
779                 else if (splitted[1] == "front")
780                         nodedef.tiledef[5].name = splitted[2];
781                 else if (splitted[1] == "all" || splitted[1] == "*")
782                         for (int i = 0; i < 6; i++)
783                                 nodedef.tiledef[i].name = splitted[2];
784                 else if (splitted[1] == "sides")
785                         for (int i = 2; i < 6; i++)
786                                 nodedef.tiledef[i].name = splitted[2];
787                 else {
788                         errorstream << override_filepath
789                                 << ":" << line_c << " Could not apply texture override \""
790                                 << line << "\": Unknown node side \""
791                                 << splitted[1] << "\"" << std::endl;
792                         continue;
793                 }
794         }
795 }
796
797 void CNodeDefManager::updateTextures(IGameDef *gamedef,
798         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
799         void *progress_callback_args)
800 {
801 #ifndef SERVER
802         infostream << "CNodeDefManager::updateTextures(): Updating "
803                 "textures in node definitions" << std::endl;
804         ITextureSource *tsrc = gamedef->tsrc();
805         IShaderSource *shdsrc = gamedef->getShaderSource();
806         scene::ISceneManager* smgr = gamedef->getSceneManager();
807         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
808
809         bool connected_glass           = g_settings->getBool("connected_glass");
810         bool opaque_water              = g_settings->getBool("opaque_water");
811         bool enable_shaders            = g_settings->getBool("enable_shaders");
812         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
813         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
814         bool enable_mesh_cache         = g_settings->getBool("enable_mesh_cache");
815         bool enable_minimap            = g_settings->getBool("enable_minimap");
816         std::string leaves_style       = g_settings->get("leaves_style");
817
818         bool use_normal_texture = enable_shaders &&
819                 (enable_bumpmapping || enable_parallax_occlusion);
820
821         u32 size = m_content_features.size();
822
823         for (u32 i = 0; i < size; i++) {
824                 ContentFeatures *f = &m_content_features[i];
825
826                 // minimap pixel color - the average color of a texture
827                 if (enable_minimap && f->tiledef[0].name != "")
828                         f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
829
830                 // Figure out the actual tiles to use
831                 TileDef tiledef[6];
832                 for (u32 j = 0; j < 6; j++) {
833                         tiledef[j] = f->tiledef[j];
834                         if (tiledef[j].name == "")
835                                 tiledef[j].name = "unknown_node.png";
836                 }
837
838                 bool is_liquid = false;
839                 bool is_water_surface = false;
840
841                 u8 material_type = (f->alpha == 255) ?
842                         TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
843
844                 switch (f->drawtype) {
845                 default:
846                 case NDT_NORMAL:
847                         f->solidness = 2;
848                         break;
849                 case NDT_AIRLIKE:
850                         f->solidness = 0;
851                         break;
852                 case NDT_LIQUID:
853                         assert(f->liquid_type == LIQUID_SOURCE);
854                         if (opaque_water)
855                                 f->alpha = 255;
856                         f->solidness = 0;
857                         is_liquid = true;
858                         break;
859                 case NDT_FLOWINGLIQUID:
860                         assert(f->liquid_type == LIQUID_FLOWING);
861                         f->solidness = 0;
862                         if (opaque_water)
863                                 f->alpha = 255;
864                         is_liquid = true;
865                         break;
866                 case NDT_GLASSLIKE:
867                         f->solidness = 0;
868                         f->visual_solidness = 1;
869                         break;
870                 case NDT_GLASSLIKE_FRAMED:
871                         f->solidness = 0;
872                         f->visual_solidness = 1;
873                         break;
874                 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
875                         f->solidness = 0;
876                         f->visual_solidness = 1;
877                         f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
878                         break;
879                 case NDT_ALLFACES:
880                         f->solidness = 0;
881                         f->visual_solidness = 1;
882                         break;
883                 case NDT_ALLFACES_OPTIONAL:
884                         if (leaves_style == "fancy") {
885                                 f->drawtype = NDT_ALLFACES;
886                                 f->solidness = 0;
887                                 f->visual_solidness = 1;
888                         } else if (leaves_style == "simple") {
889                                 for (u32 j = 0; j < 6; j++) {
890                                         if (f->tiledef_special[j].name != "")
891                                                 tiledef[j].name = f->tiledef_special[j].name;
892                                 }
893                                 f->drawtype = NDT_GLASSLIKE;
894                                 f->solidness = 0;
895                                 f->visual_solidness = 1;
896                         } else {
897                                 f->drawtype = NDT_NORMAL;
898                                 f->solidness = 2;
899                                 for (u32 i = 0; i < 6; i++)
900                                         tiledef[i].name += std::string("^[noalpha");
901                         }
902                         if (f->waving == 1)
903                                 material_type = TILE_MATERIAL_WAVING_LEAVES;
904                         break;
905                 case NDT_PLANTLIKE:
906                         f->solidness = 0;
907                         if (f->waving == 1)
908                                 material_type = TILE_MATERIAL_WAVING_PLANTS;
909                         break;
910                 case NDT_FIRELIKE:
911                         f->solidness = 0;
912                         break;
913                 case NDT_MESH:
914                         f->solidness = 0;
915                         break;
916                 case NDT_TORCHLIKE:
917                 case NDT_SIGNLIKE:
918                 case NDT_FENCELIKE:
919                 case NDT_RAILLIKE:
920                 case NDT_NODEBOX:
921                         f->solidness = 0;
922                         break;
923                 }
924
925                 if (is_liquid) {
926                         material_type = (f->alpha == 255) ?
927                                 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
928                         if (f->name == "default:water_source")
929                                 is_water_surface = true;
930                 }
931
932                 u32 tile_shader[6];
933                 for (u16 j = 0; j < 6; j++) {
934                         tile_shader[j] = shdsrc->getShader("nodes_shader",
935                                 material_type, f->drawtype);
936                 }
937
938                 if (is_water_surface) {
939                         tile_shader[0] = shdsrc->getShader("water_surface_shader",
940                                 material_type, f->drawtype);
941                 }
942
943                 // Tiles (fill in f->tiles[])
944                 for (u16 j = 0; j < 6; j++) {
945                         fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
946                                 use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type);
947                 }
948
949                 // Special tiles (fill in f->special_tiles[])
950                 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
951                         fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
952                                 tile_shader[j], use_normal_texture,
953                                 f->tiledef_special[j].backface_culling, f->alpha, material_type);
954                 }
955
956                 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
957                         // Meshnode drawtype
958                         // Read the mesh and apply scale
959                         f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
960                         if (f->mesh_ptr[0]){
961                                 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
962                                 scaleMesh(f->mesh_ptr[0], scale);
963                                 recalculateBoundingBox(f->mesh_ptr[0]);
964                                 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
965                         }
966                 } else if ((f->drawtype == NDT_NODEBOX) &&
967                                 ((f->node_box.type == NODEBOX_REGULAR) ||
968                                 (f->node_box.type == NODEBOX_FIXED)) &&
969                                 (!f->node_box.fixed.empty())) {
970                         //Convert regular nodebox nodes to meshnodes
971                         //Change the drawtype and apply scale
972                         f->drawtype = NDT_MESH;
973                         f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed);
974                         v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
975                         scaleMesh(f->mesh_ptr[0], scale);
976                         recalculateBoundingBox(f->mesh_ptr[0]);
977                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
978                 }
979
980                 //Cache 6dfacedir and wallmounted rotated clones of meshes
981                 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
982                         for (u16 j = 1; j < 24; j++) {
983                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
984                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
985                                 recalculateBoundingBox(f->mesh_ptr[j]);
986                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
987                         }
988                 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
989                         static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
990                         for (u16 j = 1; j < 6; j++) {
991                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
992                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
993                                 recalculateBoundingBox(f->mesh_ptr[j]);
994                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
995                         }
996                         rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
997                         recalculateBoundingBox(f->mesh_ptr[0]);
998                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
999                 }
1000
1001                 progress_callback(progress_callback_args, i, size);
1002         }
1003 #endif
1004 }
1005
1006
1007 #ifndef SERVER
1008 void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
1009                 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
1010                 bool backface_culling, u8 alpha, u8 material_type)
1011 {
1012         tile->shader_id     = shader_id;
1013         tile->texture       = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
1014         tile->alpha         = alpha;
1015         tile->material_type = material_type;
1016
1017         // Normal texture and shader flags texture
1018         if (use_normal_texture) {
1019                 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
1020         }
1021         tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
1022
1023         // Material flags
1024         tile->material_flags = 0;
1025         if (backface_culling)
1026                 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
1027         if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
1028                 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1029         if (tiledef->tileable_horizontal)
1030                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
1031         if (tiledef->tileable_vertical)
1032                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
1033
1034         // Animation parameters
1035         int frame_count = 1;
1036         if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
1037                 // Get texture size to determine frame count by aspect ratio
1038                 v2u32 size = tile->texture->getOriginalSize();
1039                 int frame_height = (float)size.X /
1040                                 (float)tiledef->animation.aspect_w *
1041                                 (float)tiledef->animation.aspect_h;
1042                 frame_count = size.Y / frame_height;
1043                 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
1044                 tile->animation_frame_count = frame_count;
1045                 tile->animation_frame_length_ms = frame_length_ms;
1046         }
1047
1048         if (frame_count == 1) {
1049                 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1050         } else {
1051                 std::ostringstream os(std::ios::binary);
1052                 tile->frames.resize(frame_count);
1053
1054                 for (int i = 0; i < frame_count; i++) {
1055
1056                         FrameSpec frame;
1057
1058                         os.str("");
1059                         os << tiledef->name << "^[verticalframe:"
1060                                 << frame_count << ":" << i;
1061
1062                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
1063                         if (tile->normal_texture)
1064                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
1065                         frame.flags_texture = tile->flags_texture;
1066                         tile->frames[i] = frame;
1067                 }
1068         }
1069 }
1070 #endif
1071
1072
1073 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1074 {
1075         writeU8(os, 1); // version
1076         u16 count = 0;
1077         std::ostringstream os2(std::ios::binary);
1078         for (u32 i = 0; i < m_content_features.size(); i++) {
1079                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1080                                 || i == CONTENT_UNKNOWN)
1081                         continue;
1082                 const ContentFeatures *f = &m_content_features[i];
1083                 if (f->name == "")
1084                         continue;
1085                 writeU16(os2, i);
1086                 // Wrap it in a string to allow different lengths without
1087                 // strict version incompatibilities
1088                 std::ostringstream wrapper_os(std::ios::binary);
1089                 f->serialize(wrapper_os, protocol_version);
1090                 os2<<serializeString(wrapper_os.str());
1091
1092                 // must not overflow
1093                 u16 next = count + 1;
1094                 FATAL_ERROR_IF(next < count, "Overflow");
1095                 count++;
1096         }
1097         writeU16(os, count);
1098         os << serializeLongString(os2.str());
1099 }
1100
1101
1102 void CNodeDefManager::deSerialize(std::istream &is)
1103 {
1104         clear();
1105         int version = readU8(is);
1106         if (version != 1)
1107                 throw SerializationError("unsupported NodeDefinitionManager version");
1108         u16 count = readU16(is);
1109         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1110         ContentFeatures f;
1111         for (u16 n = 0; n < count; n++) {
1112                 u16 i = readU16(is2);
1113
1114                 // Read it from the string wrapper
1115                 std::string wrapper = deSerializeString(is2);
1116                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1117                 f.deSerialize(wrapper_is);
1118
1119                 // Check error conditions
1120                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1121                         warningstream << "NodeDefManager::deSerialize(): "
1122                                 "not changing builtin node " << i << std::endl;
1123                         continue;
1124                 }
1125                 if (f.name == "") {
1126                         warningstream << "NodeDefManager::deSerialize(): "
1127                                 "received empty name" << std::endl;
1128                         continue;
1129                 }
1130
1131                 // Ignore aliases
1132                 u16 existing_id;
1133                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1134                         warningstream << "NodeDefManager::deSerialize(): "
1135                                 "already defined with different ID: " << f.name << std::endl;
1136                         continue;
1137                 }
1138
1139                 // All is ok, add node definition with the requested ID
1140                 if (i >= m_content_features.size())
1141                         m_content_features.resize((u32)(i) + 1);
1142                 m_content_features[i] = f;
1143                 addNameIdMapping(i, f.name);
1144                 verbosestream << "deserialized " << f.name << std::endl;
1145         }
1146 }
1147
1148
1149 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1150 {
1151         m_name_id_mapping.set(i, name);
1152         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1153 }
1154
1155
1156 IWritableNodeDefManager *createNodeDefManager()
1157 {
1158         return new CNodeDefManager();
1159 }
1160
1161
1162 //// Serialization of old ContentFeatures formats
1163 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1164 {
1165         if (protocol_version == 13)
1166         {
1167                 writeU8(os, 5); // version
1168                 os<<serializeString(name);
1169                 writeU16(os, groups.size());
1170                 for (ItemGroupList::const_iterator
1171                                 i = groups.begin(); i != groups.end(); ++i) {
1172                         os<<serializeString(i->first);
1173                         writeS16(os, i->second);
1174                 }
1175                 writeU8(os, drawtype);
1176                 writeF1000(os, visual_scale);
1177                 writeU8(os, 6);
1178                 for (u32 i = 0; i < 6; i++)
1179                         tiledef[i].serialize(os, protocol_version);
1180                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1181                 writeU8(os, 2);
1182                 for (u32 i = 0; i < 2; i++)
1183                         tiledef_special[i].serialize(os, protocol_version);
1184                 writeU8(os, alpha);
1185                 writeU8(os, post_effect_color.getAlpha());
1186                 writeU8(os, post_effect_color.getRed());
1187                 writeU8(os, post_effect_color.getGreen());
1188                 writeU8(os, post_effect_color.getBlue());
1189                 writeU8(os, param_type);
1190                 writeU8(os, param_type_2);
1191                 writeU8(os, is_ground_content);
1192                 writeU8(os, light_propagates);
1193                 writeU8(os, sunlight_propagates);
1194                 writeU8(os, walkable);
1195                 writeU8(os, pointable);
1196                 writeU8(os, diggable);
1197                 writeU8(os, climbable);
1198                 writeU8(os, buildable_to);
1199                 os<<serializeString(""); // legacy: used to be metadata_name
1200                 writeU8(os, liquid_type);
1201                 os<<serializeString(liquid_alternative_flowing);
1202                 os<<serializeString(liquid_alternative_source);
1203                 writeU8(os, liquid_viscosity);
1204                 writeU8(os, light_source);
1205                 writeU32(os, damage_per_second);
1206                 node_box.serialize(os, protocol_version);
1207                 selection_box.serialize(os, protocol_version);
1208                 writeU8(os, legacy_facedir_simple);
1209                 writeU8(os, legacy_wallmounted);
1210                 serializeSimpleSoundSpec(sound_footstep, os);
1211                 serializeSimpleSoundSpec(sound_dig, os);
1212                 serializeSimpleSoundSpec(sound_dug, os);
1213         }
1214         else if (protocol_version > 13 && protocol_version < 24) {
1215                 writeU8(os, 6); // version
1216                 os<<serializeString(name);
1217                 writeU16(os, groups.size());
1218                 for (ItemGroupList::const_iterator
1219                         i = groups.begin(); i != groups.end(); ++i) {
1220                                 os<<serializeString(i->first);
1221                                 writeS16(os, i->second);
1222                 }
1223                 writeU8(os, drawtype);
1224                 writeF1000(os, visual_scale);
1225                 writeU8(os, 6);
1226                 for (u32 i = 0; i < 6; i++)
1227                         tiledef[i].serialize(os, protocol_version);
1228                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1229                 writeU8(os, 2);
1230                 for (u32 i = 0; i < 2; i++)
1231                         tiledef_special[i].serialize(os, protocol_version);
1232                 writeU8(os, alpha);
1233                 writeU8(os, post_effect_color.getAlpha());
1234                 writeU8(os, post_effect_color.getRed());
1235                 writeU8(os, post_effect_color.getGreen());
1236                 writeU8(os, post_effect_color.getBlue());
1237                 writeU8(os, param_type);
1238                 writeU8(os, param_type_2);
1239                 writeU8(os, is_ground_content);
1240                 writeU8(os, light_propagates);
1241                 writeU8(os, sunlight_propagates);
1242                 writeU8(os, walkable);
1243                 writeU8(os, pointable);
1244                 writeU8(os, diggable);
1245                 writeU8(os, climbable);
1246                 writeU8(os, buildable_to);
1247                 os<<serializeString(""); // legacy: used to be metadata_name
1248                 writeU8(os, liquid_type);
1249                 os<<serializeString(liquid_alternative_flowing);
1250                 os<<serializeString(liquid_alternative_source);
1251                 writeU8(os, liquid_viscosity);
1252                 writeU8(os, liquid_renewable);
1253                 writeU8(os, light_source);
1254                 writeU32(os, damage_per_second);
1255                 node_box.serialize(os, protocol_version);
1256                 selection_box.serialize(os, protocol_version);
1257                 writeU8(os, legacy_facedir_simple);
1258                 writeU8(os, legacy_wallmounted);
1259                 serializeSimpleSoundSpec(sound_footstep, os);
1260                 serializeSimpleSoundSpec(sound_dig, os);
1261                 serializeSimpleSoundSpec(sound_dug, os);
1262                 writeU8(os, rightclickable);
1263                 writeU8(os, drowning);
1264                 writeU8(os, leveled);
1265                 writeU8(os, liquid_range);
1266         } else
1267                 throw SerializationError("ContentFeatures::serialize(): "
1268                         "Unsupported version requested");
1269 }
1270
1271 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1272 {
1273         if (version == 5) // In PROTOCOL_VERSION 13
1274         {
1275                 name = deSerializeString(is);
1276                 groups.clear();
1277                 u32 groups_size = readU16(is);
1278                 for(u32 i=0; i<groups_size; i++){
1279                         std::string name = deSerializeString(is);
1280                         int value = readS16(is);
1281                         groups[name] = value;
1282                 }
1283                 drawtype = (enum NodeDrawType)readU8(is);
1284
1285                 visual_scale = readF1000(is);
1286                 if (readU8(is) != 6)
1287                         throw SerializationError("unsupported tile count");
1288                 for (u32 i = 0; i < 6; i++)
1289                         tiledef[i].deSerialize(is, version, drawtype);
1290                 if (readU8(is) != CF_SPECIAL_COUNT)
1291                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1292                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1293                         tiledef_special[i].deSerialize(is, version, drawtype);
1294                 alpha = readU8(is);
1295                 post_effect_color.setAlpha(readU8(is));
1296                 post_effect_color.setRed(readU8(is));
1297                 post_effect_color.setGreen(readU8(is));
1298                 post_effect_color.setBlue(readU8(is));
1299                 param_type = (enum ContentParamType)readU8(is);
1300                 param_type_2 = (enum ContentParamType2)readU8(is);
1301                 is_ground_content = readU8(is);
1302                 light_propagates = readU8(is);
1303                 sunlight_propagates = readU8(is);
1304                 walkable = readU8(is);
1305                 pointable = readU8(is);
1306                 diggable = readU8(is);
1307                 climbable = readU8(is);
1308                 buildable_to = readU8(is);
1309                 deSerializeString(is); // legacy: used to be metadata_name
1310                 liquid_type = (enum LiquidType)readU8(is);
1311                 liquid_alternative_flowing = deSerializeString(is);
1312                 liquid_alternative_source = deSerializeString(is);
1313                 liquid_viscosity = readU8(is);
1314                 light_source = readU8(is);
1315                 damage_per_second = readU32(is);
1316                 node_box.deSerialize(is);
1317                 selection_box.deSerialize(is);
1318                 legacy_facedir_simple = readU8(is);
1319                 legacy_wallmounted = readU8(is);
1320                 deSerializeSimpleSoundSpec(sound_footstep, is);
1321                 deSerializeSimpleSoundSpec(sound_dig, is);
1322                 deSerializeSimpleSoundSpec(sound_dug, is);
1323         } else if (version == 6) {
1324                 name = deSerializeString(is);
1325                 groups.clear();
1326                 u32 groups_size = readU16(is);
1327                 for (u32 i = 0; i < groups_size; i++) {
1328                         std::string name = deSerializeString(is);
1329                         int     value = readS16(is);
1330                         groups[name] = value;
1331                 }
1332                 drawtype = (enum NodeDrawType)readU8(is);
1333                 visual_scale = readF1000(is);
1334                 if (readU8(is) != 6)
1335                         throw SerializationError("unsupported tile count");
1336                 for (u32 i = 0; i < 6; i++)
1337                         tiledef[i].deSerialize(is, version, drawtype);
1338                 // CF_SPECIAL_COUNT in version 6 = 2
1339                 if (readU8(is) != 2)
1340                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1341                 for (u32 i = 0; i < 2; i++)
1342                         tiledef_special[i].deSerialize(is, version, drawtype);
1343                 alpha = readU8(is);
1344                 post_effect_color.setAlpha(readU8(is));
1345                 post_effect_color.setRed(readU8(is));
1346                 post_effect_color.setGreen(readU8(is));
1347                 post_effect_color.setBlue(readU8(is));
1348                 param_type = (enum ContentParamType)readU8(is);
1349                 param_type_2 = (enum ContentParamType2)readU8(is);
1350                 is_ground_content = readU8(is);
1351                 light_propagates = readU8(is);
1352                 sunlight_propagates = readU8(is);
1353                 walkable = readU8(is);
1354                 pointable = readU8(is);
1355                 diggable = readU8(is);
1356                 climbable = readU8(is);
1357                 buildable_to = readU8(is);
1358                 deSerializeString(is); // legacy: used to be metadata_name
1359                 liquid_type = (enum LiquidType)readU8(is);
1360                 liquid_alternative_flowing = deSerializeString(is);
1361                 liquid_alternative_source = deSerializeString(is);
1362                 liquid_viscosity = readU8(is);
1363                 liquid_renewable = readU8(is);
1364                 light_source = readU8(is);
1365                 damage_per_second = readU32(is);
1366                 node_box.deSerialize(is);
1367                 selection_box.deSerialize(is);
1368                 legacy_facedir_simple = readU8(is);
1369                 legacy_wallmounted = readU8(is);
1370                 deSerializeSimpleSoundSpec(sound_footstep, is);
1371                 deSerializeSimpleSoundSpec(sound_dig, is);
1372                 deSerializeSimpleSoundSpec(sound_dug, is);
1373                 rightclickable = readU8(is);
1374                 drowning = readU8(is);
1375                 leveled = readU8(is);
1376                 liquid_range = readU8(is);
1377         } else {
1378                 throw SerializationError("unsupported ContentFeatures version");
1379         }
1380 }
1381
1382
1383 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1384 {
1385         return m_node_registration_complete;
1386 }
1387
1388
1389 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1390 {
1391         m_node_registration_complete = completed;
1392 }
1393
1394
1395 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1396 {
1397         nr->m_ndef = this;
1398         if (m_node_registration_complete)
1399                 nr->nodeResolveInternal();
1400         else
1401                 m_pending_resolve_callbacks.push_back(nr);
1402 }
1403
1404
1405 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1406 {
1407         size_t len = m_pending_resolve_callbacks.size();
1408         for (size_t i = 0; i != len; i++) {
1409                 if (nr != m_pending_resolve_callbacks[i])
1410                         continue;
1411
1412                 len--;
1413                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1414                 m_pending_resolve_callbacks.resize(len);
1415                 return true;
1416         }
1417
1418         return false;
1419 }
1420
1421
1422 void CNodeDefManager::runNodeResolveCallbacks()
1423 {
1424         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1425                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1426                 nr->nodeResolveInternal();
1427         }
1428
1429         m_pending_resolve_callbacks.clear();
1430 }
1431
1432
1433 void CNodeDefManager::resetNodeResolveState()
1434 {
1435         m_node_registration_complete = false;
1436         m_pending_resolve_callbacks.clear();
1437 }
1438
1439
1440 ////
1441 //// NodeResolver
1442 ////
1443
1444 NodeResolver::NodeResolver()
1445 {
1446         m_ndef            = NULL;
1447         m_nodenames_idx   = 0;
1448         m_nnlistsizes_idx = 0;
1449         m_resolve_done    = false;
1450
1451         m_nodenames.reserve(16);
1452         m_nnlistsizes.reserve(4);
1453 }
1454
1455
1456 NodeResolver::~NodeResolver()
1457 {
1458         if (!m_resolve_done && m_ndef)
1459                 m_ndef->cancelNodeResolveCallback(this);
1460 }
1461
1462
1463 void NodeResolver::nodeResolveInternal()
1464 {
1465         m_nodenames_idx   = 0;
1466         m_nnlistsizes_idx = 0;
1467
1468         resolveNodeNames();
1469         m_resolve_done = true;
1470
1471         m_nodenames.clear();
1472         m_nnlistsizes.clear();
1473 }
1474
1475
1476 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1477         const std::string &node_alt, content_t c_fallback)
1478 {
1479         if (m_nodenames_idx == m_nodenames.size()) {
1480                 *result_out = c_fallback;
1481                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1482                 return false;
1483         }
1484
1485         content_t c;
1486         std::string name = m_nodenames[m_nodenames_idx++];
1487
1488         bool success = m_ndef->getId(name, c);
1489         if (!success && node_alt != "") {
1490                 name = node_alt;
1491                 success = m_ndef->getId(name, c);
1492         }
1493
1494         if (!success) {
1495                 errorstream << "NodeResolver: failed to resolve node name '" << name
1496                         << "'." << std::endl;
1497                 c = c_fallback;
1498         }
1499
1500         *result_out = c;
1501         return success;
1502 }
1503
1504
1505 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1506         bool all_required, content_t c_fallback)
1507 {
1508         bool success = true;
1509
1510         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1511                 errorstream << "NodeResolver: no more node lists" << std::endl;
1512                 return false;
1513         }
1514
1515         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1516
1517         while (length--) {
1518                 if (m_nodenames_idx == m_nodenames.size()) {
1519                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1520                         return false;
1521                 }
1522
1523                 content_t c;
1524                 std::string &name = m_nodenames[m_nodenames_idx++];
1525
1526                 if (name.substr(0,6) != "group:") {
1527                         if (m_ndef->getId(name, c)) {
1528                                 result_out->push_back(c);
1529                         } else if (all_required) {
1530                                 errorstream << "NodeResolver: failed to resolve node name '"
1531                                         << name << "'." << std::endl;
1532                                 result_out->push_back(c_fallback);
1533                                 success = false;
1534                         }
1535                 } else {
1536                         std::set<content_t> cids;
1537                         std::set<content_t>::iterator it;
1538                         m_ndef->getIds(name, cids);
1539                         for (it = cids.begin(); it != cids.end(); ++it)
1540                                 result_out->push_back(*it);
1541                 }
1542         }
1543
1544         return success;
1545 }