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