Allow nodes to specify which sides to connect to.
[oweals/minetest.git] / src / nodedef.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "nodedef.h"
21
22 #include "itemdef.h"
23 #ifndef SERVER
24 #include "client/tile.h"
25 #include "mesh.h"
26 #include <IMeshManipulator.h>
27 #endif
28 #include "log.h"
29 #include "settings.h"
30 #include "nameidmapping.h"
31 #include "util/numeric.h"
32 #include "util/serialize.h"
33 #include "exceptions.h"
34 #include "debug.h"
35 #include "gamedef.h"
36 #include "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         for (u16 i = 0; i < connects_to_size; i++)
483                 connects_to_ids.insert(readU16(is));
484         connect_sides = readU8(is);
485         }catch(SerializationError &e) {};
486 }
487
488 /*
489         CNodeDefManager
490 */
491
492 class CNodeDefManager: public IWritableNodeDefManager {
493 public:
494         CNodeDefManager();
495         virtual ~CNodeDefManager();
496         void clear();
497         virtual IWritableNodeDefManager *clone();
498         inline virtual const ContentFeatures& get(content_t c) const;
499         inline virtual const ContentFeatures& get(const MapNode &n) const;
500         virtual bool getId(const std::string &name, content_t &result) const;
501         virtual content_t getId(const std::string &name) const;
502         virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
503         virtual const ContentFeatures& get(const std::string &name) const;
504         content_t allocateId();
505         virtual content_t set(const std::string &name, const ContentFeatures &def);
506         virtual content_t allocateDummy(const std::string &name);
507         virtual void updateAliases(IItemDefManager *idef);
508         virtual void applyTextureOverrides(const std::string &override_filepath);
509         virtual void updateTextures(IGameDef *gamedef,
510                 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
511                 void *progress_cbk_args);
512         void serialize(std::ostream &os, u16 protocol_version) const;
513         void deSerialize(std::istream &is);
514
515         inline virtual bool getNodeRegistrationStatus() const;
516         inline virtual void setNodeRegistrationStatus(bool completed);
517
518         virtual void pendNodeResolve(NodeResolver *nr);
519         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
520         virtual void runNodeResolveCallbacks();
521         virtual void resetNodeResolveState();
522         virtual void mapNodeboxConnections();
523         virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
524
525 private:
526         void addNameIdMapping(content_t i, std::string name);
527 #ifndef SERVER
528         void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
529                 u32 shader_id, bool use_normal_texture, bool backface_culling,
530                 u8 alpha, u8 material_type);
531 #endif
532
533         // Features indexed by id
534         std::vector<ContentFeatures> m_content_features;
535
536         // A mapping for fast converting back and forth between names and ids
537         NameIdMapping m_name_id_mapping;
538
539         // Like m_name_id_mapping, but only from names to ids, and includes
540         // item aliases too. Updated by updateAliases()
541         // Note: Not serialized.
542
543         std::map<std::string, content_t> m_name_id_mapping_with_aliases;
544
545         // A mapping from groups to a list of content_ts (and their levels)
546         // that belong to it.  Necessary for a direct lookup in getIds().
547         // Note: Not serialized.
548         std::map<std::string, GroupItems> m_group_to_items;
549
550         // Next possibly free id
551         content_t m_next_id;
552
553         // NodeResolvers to callback once node registration has ended
554         std::vector<NodeResolver *> m_pending_resolve_callbacks;
555
556         // True when all nodes have been registered
557         bool m_node_registration_complete;
558 };
559
560
561 CNodeDefManager::CNodeDefManager()
562 {
563         clear();
564 }
565
566
567 CNodeDefManager::~CNodeDefManager()
568 {
569 #ifndef SERVER
570         for (u32 i = 0; i < m_content_features.size(); i++) {
571                 ContentFeatures *f = &m_content_features[i];
572                 for (u32 j = 0; j < 24; j++) {
573                         if (f->mesh_ptr[j])
574                                 f->mesh_ptr[j]->drop();
575                 }
576         }
577 #endif
578 }
579
580
581 void CNodeDefManager::clear()
582 {
583         m_content_features.clear();
584         m_name_id_mapping.clear();
585         m_name_id_mapping_with_aliases.clear();
586         m_group_to_items.clear();
587         m_next_id = 0;
588
589         resetNodeResolveState();
590
591         u32 initial_length = 0;
592         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
593         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
594         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
595         m_content_features.resize(initial_length);
596
597         // Set CONTENT_UNKNOWN
598         {
599                 ContentFeatures f;
600                 f.name = "unknown";
601                 // Insert directly into containers
602                 content_t c = CONTENT_UNKNOWN;
603                 m_content_features[c] = f;
604                 addNameIdMapping(c, f.name);
605         }
606
607         // Set CONTENT_AIR
608         {
609                 ContentFeatures f;
610                 f.name                = "air";
611                 f.drawtype            = NDT_AIRLIKE;
612                 f.param_type          = CPT_LIGHT;
613                 f.light_propagates    = true;
614                 f.sunlight_propagates = true;
615                 f.walkable            = false;
616                 f.pointable           = false;
617                 f.diggable            = false;
618                 f.buildable_to        = true;
619                 f.floodable           = true;
620                 f.is_ground_content   = true;
621                 // Insert directly into containers
622                 content_t c = CONTENT_AIR;
623                 m_content_features[c] = f;
624                 addNameIdMapping(c, f.name);
625         }
626
627         // Set CONTENT_IGNORE
628         {
629                 ContentFeatures f;
630                 f.name                = "ignore";
631                 f.drawtype            = NDT_AIRLIKE;
632                 f.param_type          = CPT_NONE;
633                 f.light_propagates    = false;
634                 f.sunlight_propagates = false;
635                 f.walkable            = false;
636                 f.pointable           = false;
637                 f.diggable            = false;
638                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
639                 f.is_ground_content   = true;
640                 // Insert directly into containers
641                 content_t c = CONTENT_IGNORE;
642                 m_content_features[c] = f;
643                 addNameIdMapping(c, f.name);
644         }
645 }
646
647
648 IWritableNodeDefManager *CNodeDefManager::clone()
649 {
650         CNodeDefManager *mgr = new CNodeDefManager();
651         *mgr = *this;
652         return mgr;
653 }
654
655
656 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
657 {
658         return c < m_content_features.size()
659                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
660 }
661
662
663 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
664 {
665         return get(n.getContent());
666 }
667
668
669 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
670 {
671         std::map<std::string, content_t>::const_iterator
672                 i = m_name_id_mapping_with_aliases.find(name);
673         if(i == m_name_id_mapping_with_aliases.end())
674                 return false;
675         result = i->second;
676         return true;
677 }
678
679
680 content_t CNodeDefManager::getId(const std::string &name) const
681 {
682         content_t id = CONTENT_IGNORE;
683         getId(name, id);
684         return id;
685 }
686
687
688 bool CNodeDefManager::getIds(const std::string &name,
689                 std::set<content_t> &result) const
690 {
691         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
692         if (name.substr(0,6) != "group:") {
693                 content_t id = CONTENT_IGNORE;
694                 bool exists = getId(name, id);
695                 if (exists)
696                         result.insert(id);
697                 return exists;
698         }
699         std::string group = name.substr(6);
700
701         std::map<std::string, GroupItems>::const_iterator
702                 i = m_group_to_items.find(group);
703         if (i == m_group_to_items.end())
704                 return true;
705
706         const GroupItems &items = i->second;
707         for (GroupItems::const_iterator j = items.begin();
708                 j != items.end(); ++j) {
709                 if ((*j).second != 0)
710                         result.insert((*j).first);
711         }
712         //printf("getIds: %dus\n", t.stop());
713         return true;
714 }
715
716
717 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
718 {
719         content_t id = CONTENT_UNKNOWN;
720         getId(name, id);
721         return get(id);
722 }
723
724
725 // returns CONTENT_IGNORE if no free ID found
726 content_t CNodeDefManager::allocateId()
727 {
728         for (content_t id = m_next_id;
729                         id >= m_next_id; // overflow?
730                         ++id) {
731                 while (id >= m_content_features.size()) {
732                         m_content_features.push_back(ContentFeatures());
733                 }
734                 const ContentFeatures &f = m_content_features[id];
735                 if (f.name == "") {
736                         m_next_id = id + 1;
737                         return id;
738                 }
739         }
740         // If we arrive here, an overflow occurred in id.
741         // That means no ID was found
742         return CONTENT_IGNORE;
743 }
744
745
746 // IWritableNodeDefManager
747 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
748 {
749         // Pre-conditions
750         assert(name != "");
751         assert(name == def.name);
752
753         // Don't allow redefining ignore (but allow air and unknown)
754         if (name == "ignore") {
755                 warningstream << "NodeDefManager: Ignoring "
756                         "CONTENT_IGNORE redefinition"<<std::endl;
757                 return CONTENT_IGNORE;
758         }
759
760         content_t id = CONTENT_IGNORE;
761         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
762                 // Get new id
763                 id = allocateId();
764                 if (id == CONTENT_IGNORE) {
765                         warningstream << "NodeDefManager: Absolute "
766                                 "limit reached" << std::endl;
767                         return CONTENT_IGNORE;
768                 }
769                 assert(id != CONTENT_IGNORE);
770                 addNameIdMapping(id, name);
771         }
772         m_content_features[id] = def;
773         verbosestream << "NodeDefManager: registering content id \"" << id
774                 << "\": name=\"" << def.name << "\""<<std::endl;
775
776         // Add this content to the list of all groups it belongs to
777         // FIXME: This should remove a node from groups it no longer
778         // belongs to when a node is re-registered
779         for (ItemGroupList::const_iterator i = def.groups.begin();
780                 i != def.groups.end(); ++i) {
781                 std::string group_name = i->first;
782
783                 std::map<std::string, GroupItems>::iterator
784                         j = m_group_to_items.find(group_name);
785                 if (j == m_group_to_items.end()) {
786                         m_group_to_items[group_name].push_back(
787                                 std::make_pair(id, i->second));
788                 } else {
789                         GroupItems &items = j->second;
790                         items.push_back(std::make_pair(id, i->second));
791                 }
792         }
793         return id;
794 }
795
796
797 content_t CNodeDefManager::allocateDummy(const std::string &name)
798 {
799         assert(name != "");     // Pre-condition
800         ContentFeatures f;
801         f.name = name;
802         return set(name, f);
803 }
804
805
806 void CNodeDefManager::updateAliases(IItemDefManager *idef)
807 {
808         std::set<std::string> all = idef->getAll();
809         m_name_id_mapping_with_aliases.clear();
810         for (std::set<std::string>::iterator
811                         i = all.begin(); i != all.end(); ++i) {
812                 std::string name = *i;
813                 std::string convert_to = idef->getAlias(name);
814                 content_t id;
815                 if (m_name_id_mapping.getId(convert_to, id)) {
816                         m_name_id_mapping_with_aliases.insert(
817                                 std::make_pair(name, id));
818                 }
819         }
820 }
821
822 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
823 {
824         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
825                 "overrides to textures from " << override_filepath << std::endl;
826
827         std::ifstream infile(override_filepath.c_str());
828         std::string line;
829         int line_c = 0;
830         while (std::getline(infile, line)) {
831                 line_c++;
832                 if (trim(line) == "")
833                         continue;
834                 std::vector<std::string> splitted = str_split(line, ' ');
835                 if (splitted.size() != 3) {
836                         errorstream << override_filepath
837                                 << ":" << line_c << " Could not apply texture override \""
838                                 << line << "\": Syntax error" << std::endl;
839                         continue;
840                 }
841
842                 content_t id;
843                 if (!getId(splitted[0], id)) {
844                         errorstream << override_filepath
845                                 << ":" << line_c << " Could not apply texture override \""
846                                 << line << "\": Unknown node \""
847                                 << splitted[0] << "\"" << std::endl;
848                         continue;
849                 }
850
851                 ContentFeatures &nodedef = m_content_features[id];
852
853                 if (splitted[1] == "top")
854                         nodedef.tiledef[0].name = splitted[2];
855                 else if (splitted[1] == "bottom")
856                         nodedef.tiledef[1].name = splitted[2];
857                 else if (splitted[1] == "right")
858                         nodedef.tiledef[2].name = splitted[2];
859                 else if (splitted[1] == "left")
860                         nodedef.tiledef[3].name = splitted[2];
861                 else if (splitted[1] == "back")
862                         nodedef.tiledef[4].name = splitted[2];
863                 else if (splitted[1] == "front")
864                         nodedef.tiledef[5].name = splitted[2];
865                 else if (splitted[1] == "all" || splitted[1] == "*")
866                         for (int i = 0; i < 6; i++)
867                                 nodedef.tiledef[i].name = splitted[2];
868                 else if (splitted[1] == "sides")
869                         for (int i = 2; i < 6; i++)
870                                 nodedef.tiledef[i].name = splitted[2];
871                 else {
872                         errorstream << override_filepath
873                                 << ":" << line_c << " Could not apply texture override \""
874                                 << line << "\": Unknown node side \""
875                                 << splitted[1] << "\"" << std::endl;
876                         continue;
877                 }
878         }
879 }
880
881 void CNodeDefManager::updateTextures(IGameDef *gamedef,
882         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
883         void *progress_callback_args)
884 {
885 #ifndef SERVER
886         infostream << "CNodeDefManager::updateTextures(): Updating "
887                 "textures in node definitions" << std::endl;
888         ITextureSource *tsrc = gamedef->tsrc();
889         IShaderSource *shdsrc = gamedef->getShaderSource();
890         scene::ISceneManager* smgr = gamedef->getSceneManager();
891         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
892
893         bool connected_glass           = g_settings->getBool("connected_glass");
894         bool opaque_water              = g_settings->getBool("opaque_water");
895         bool enable_shaders            = g_settings->getBool("enable_shaders");
896         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
897         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
898         bool enable_mesh_cache         = g_settings->getBool("enable_mesh_cache");
899         bool enable_minimap            = g_settings->getBool("enable_minimap");
900         std::string leaves_style       = g_settings->get("leaves_style");
901
902         bool use_normal_texture = enable_shaders &&
903                 (enable_bumpmapping || enable_parallax_occlusion);
904
905         u32 size = m_content_features.size();
906
907         for (u32 i = 0; i < size; i++) {
908                 ContentFeatures *f = &m_content_features[i];
909
910                 // minimap pixel color - the average color of a texture
911                 if (enable_minimap && f->tiledef[0].name != "")
912                         f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
913
914                 // Figure out the actual tiles to use
915                 TileDef tiledef[6];
916                 for (u32 j = 0; j < 6; j++) {
917                         tiledef[j] = f->tiledef[j];
918                         if (tiledef[j].name == "")
919                                 tiledef[j].name = "unknown_node.png";
920                 }
921
922                 bool is_liquid = false;
923                 bool is_water_surface = false;
924
925                 u8 material_type = (f->alpha == 255) ?
926                         TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
927
928                 switch (f->drawtype) {
929                 default:
930                 case NDT_NORMAL:
931                         f->solidness = 2;
932                         break;
933                 case NDT_AIRLIKE:
934                         f->solidness = 0;
935                         break;
936                 case NDT_LIQUID:
937                         assert(f->liquid_type == LIQUID_SOURCE);
938                         if (opaque_water)
939                                 f->alpha = 255;
940                         f->solidness = 1;
941                         is_liquid = true;
942                         break;
943                 case NDT_FLOWINGLIQUID:
944                         assert(f->liquid_type == LIQUID_FLOWING);
945                         f->solidness = 0;
946                         if (opaque_water)
947                                 f->alpha = 255;
948                         is_liquid = true;
949                         break;
950                 case NDT_GLASSLIKE:
951                         f->solidness = 0;
952                         f->visual_solidness = 1;
953                         break;
954                 case NDT_GLASSLIKE_FRAMED:
955                         f->solidness = 0;
956                         f->visual_solidness = 1;
957                         break;
958                 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
959                         f->solidness = 0;
960                         f->visual_solidness = 1;
961                         f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
962                         break;
963                 case NDT_ALLFACES:
964                         f->solidness = 0;
965                         f->visual_solidness = 1;
966                         break;
967                 case NDT_ALLFACES_OPTIONAL:
968                         if (leaves_style == "fancy") {
969                                 f->drawtype = NDT_ALLFACES;
970                                 f->solidness = 0;
971                                 f->visual_solidness = 1;
972                         } else if (leaves_style == "simple") {
973                                 for (u32 j = 0; j < 6; j++) {
974                                         if (f->tiledef_special[j].name != "")
975                                                 tiledef[j].name = f->tiledef_special[j].name;
976                                 }
977                                 f->drawtype = NDT_GLASSLIKE;
978                                 f->solidness = 0;
979                                 f->visual_solidness = 1;
980                         } else {
981                                 f->drawtype = NDT_NORMAL;
982                                 f->solidness = 2;
983                                 for (u32 i = 0; i < 6; i++)
984                                         tiledef[i].name += std::string("^[noalpha");
985                         }
986                         if (f->waving == 1)
987                                 material_type = TILE_MATERIAL_WAVING_LEAVES;
988                         break;
989                 case NDT_PLANTLIKE:
990                         f->solidness = 0;
991                         if (f->waving == 1)
992                                 material_type = TILE_MATERIAL_WAVING_PLANTS;
993                         break;
994                 case NDT_FIRELIKE:
995                         f->solidness = 0;
996                         break;
997                 case NDT_MESH:
998                         f->solidness = 0;
999                         break;
1000                 case NDT_TORCHLIKE:
1001                 case NDT_SIGNLIKE:
1002                 case NDT_FENCELIKE:
1003                 case NDT_RAILLIKE:
1004                 case NDT_NODEBOX:
1005                         f->solidness = 0;
1006                         break;
1007                 }
1008
1009                 if (is_liquid) {
1010                         material_type = (f->alpha == 255) ?
1011                                 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
1012                         if (f->name == "default:water_source")
1013                                 is_water_surface = true;
1014                 }
1015
1016                 u32 tile_shader[6];
1017                 for (u16 j = 0; j < 6; j++) {
1018                         tile_shader[j] = shdsrc->getShader("nodes_shader",
1019                                 material_type, f->drawtype);
1020                 }
1021
1022                 if (is_water_surface) {
1023                         tile_shader[0] = shdsrc->getShader("water_surface_shader",
1024                                 material_type, f->drawtype);
1025                 }
1026
1027                 // Tiles (fill in f->tiles[])
1028                 for (u16 j = 0; j < 6; j++) {
1029                         fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
1030                                 use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type);
1031                 }
1032
1033                 // Special tiles (fill in f->special_tiles[])
1034                 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
1035                         fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
1036                                 tile_shader[j], use_normal_texture,
1037                                 f->tiledef_special[j].backface_culling, f->alpha, material_type);
1038                 }
1039
1040                 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
1041                         // Meshnode drawtype
1042                         // Read the mesh and apply scale
1043                         f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
1044                         if (f->mesh_ptr[0]){
1045                                 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
1046                                 scaleMesh(f->mesh_ptr[0], scale);
1047                                 recalculateBoundingBox(f->mesh_ptr[0]);
1048                                 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1049                         }
1050                 } else if ((f->drawtype == NDT_NODEBOX) &&
1051                                 ((f->node_box.type == NODEBOX_REGULAR) ||
1052                                 (f->node_box.type == NODEBOX_FIXED)) &&
1053                                 (!f->node_box.fixed.empty())) {
1054                         //Convert regular nodebox nodes to meshnodes
1055                         //Change the drawtype and apply scale
1056                         f->drawtype = NDT_MESH;
1057                         f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed);
1058                         v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
1059                         scaleMesh(f->mesh_ptr[0], scale);
1060                         recalculateBoundingBox(f->mesh_ptr[0]);
1061                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1062                 }
1063
1064                 //Cache 6dfacedir and wallmounted rotated clones of meshes
1065                 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
1066                         for (u16 j = 1; j < 24; j++) {
1067                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1068                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
1069                                 recalculateBoundingBox(f->mesh_ptr[j]);
1070                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1071                         }
1072                 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
1073                         static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
1074                         for (u16 j = 1; j < 6; j++) {
1075                                 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1076                                 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
1077                                 recalculateBoundingBox(f->mesh_ptr[j]);
1078                                 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1079                         }
1080                         rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
1081                         recalculateBoundingBox(f->mesh_ptr[0]);
1082                         meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1083                 }
1084
1085                 progress_callback(progress_callback_args, i, size);
1086         }
1087 #endif
1088 }
1089
1090
1091 #ifndef SERVER
1092 void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
1093                 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
1094                 bool backface_culling, u8 alpha, u8 material_type)
1095 {
1096         tile->shader_id     = shader_id;
1097         tile->texture       = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
1098         tile->alpha         = alpha;
1099         tile->material_type = material_type;
1100
1101         // Normal texture and shader flags texture
1102         if (use_normal_texture) {
1103                 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
1104         }
1105         tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
1106
1107         // Material flags
1108         tile->material_flags = 0;
1109         if (backface_culling)
1110                 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
1111         if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
1112                 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1113         if (tiledef->tileable_horizontal)
1114                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
1115         if (tiledef->tileable_vertical)
1116                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
1117
1118         // Animation parameters
1119         int frame_count = 1;
1120         if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
1121                 // Get texture size to determine frame count by aspect ratio
1122                 v2u32 size = tile->texture->getOriginalSize();
1123                 int frame_height = (float)size.X /
1124                                 (float)tiledef->animation.aspect_w *
1125                                 (float)tiledef->animation.aspect_h;
1126                 frame_count = size.Y / frame_height;
1127                 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
1128                 tile->animation_frame_count = frame_count;
1129                 tile->animation_frame_length_ms = frame_length_ms;
1130         }
1131
1132         if (frame_count == 1) {
1133                 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1134         } else {
1135                 std::ostringstream os(std::ios::binary);
1136                 tile->frames.resize(frame_count);
1137
1138                 for (int i = 0; i < frame_count; i++) {
1139
1140                         FrameSpec frame;
1141
1142                         os.str("");
1143                         os << tiledef->name << "^[verticalframe:"
1144                                 << frame_count << ":" << i;
1145
1146                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
1147                         if (tile->normal_texture)
1148                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
1149                         frame.flags_texture = tile->flags_texture;
1150                         tile->frames[i] = frame;
1151                 }
1152         }
1153 }
1154 #endif
1155
1156
1157 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1158 {
1159         writeU8(os, 1); // version
1160         u16 count = 0;
1161         std::ostringstream os2(std::ios::binary);
1162         for (u32 i = 0; i < m_content_features.size(); i++) {
1163                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1164                                 || i == CONTENT_UNKNOWN)
1165                         continue;
1166                 const ContentFeatures *f = &m_content_features[i];
1167                 if (f->name == "")
1168                         continue;
1169                 writeU16(os2, i);
1170                 // Wrap it in a string to allow different lengths without
1171                 // strict version incompatibilities
1172                 std::ostringstream wrapper_os(std::ios::binary);
1173                 f->serialize(wrapper_os, protocol_version);
1174                 os2<<serializeString(wrapper_os.str());
1175
1176                 // must not overflow
1177                 u16 next = count + 1;
1178                 FATAL_ERROR_IF(next < count, "Overflow");
1179                 count++;
1180         }
1181         writeU16(os, count);
1182         os << serializeLongString(os2.str());
1183 }
1184
1185
1186 void CNodeDefManager::deSerialize(std::istream &is)
1187 {
1188         clear();
1189         int version = readU8(is);
1190         if (version != 1)
1191                 throw SerializationError("unsupported NodeDefinitionManager version");
1192         u16 count = readU16(is);
1193         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1194         ContentFeatures f;
1195         for (u16 n = 0; n < count; n++) {
1196                 u16 i = readU16(is2);
1197
1198                 // Read it from the string wrapper
1199                 std::string wrapper = deSerializeString(is2);
1200                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1201                 f.deSerialize(wrapper_is);
1202
1203                 // Check error conditions
1204                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1205                         warningstream << "NodeDefManager::deSerialize(): "
1206                                 "not changing builtin node " << i << std::endl;
1207                         continue;
1208                 }
1209                 if (f.name == "") {
1210                         warningstream << "NodeDefManager::deSerialize(): "
1211                                 "received empty name" << std::endl;
1212                         continue;
1213                 }
1214
1215                 // Ignore aliases
1216                 u16 existing_id;
1217                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1218                         warningstream << "NodeDefManager::deSerialize(): "
1219                                 "already defined with different ID: " << f.name << std::endl;
1220                         continue;
1221                 }
1222
1223                 // All is ok, add node definition with the requested ID
1224                 if (i >= m_content_features.size())
1225                         m_content_features.resize((u32)(i) + 1);
1226                 m_content_features[i] = f;
1227                 addNameIdMapping(i, f.name);
1228                 verbosestream << "deserialized " << f.name << std::endl;
1229         }
1230 }
1231
1232
1233 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1234 {
1235         m_name_id_mapping.set(i, name);
1236         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1237 }
1238
1239
1240 IWritableNodeDefManager *createNodeDefManager()
1241 {
1242         return new CNodeDefManager();
1243 }
1244
1245
1246 //// Serialization of old ContentFeatures formats
1247 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1248 {
1249         if (protocol_version == 13)
1250         {
1251                 writeU8(os, 5); // version
1252                 os<<serializeString(name);
1253                 writeU16(os, groups.size());
1254                 for (ItemGroupList::const_iterator
1255                                 i = groups.begin(); i != groups.end(); ++i) {
1256                         os<<serializeString(i->first);
1257                         writeS16(os, i->second);
1258                 }
1259                 writeU8(os, drawtype);
1260                 writeF1000(os, visual_scale);
1261                 writeU8(os, 6);
1262                 for (u32 i = 0; i < 6; i++)
1263                         tiledef[i].serialize(os, protocol_version);
1264                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1265                 writeU8(os, 2);
1266                 for (u32 i = 0; i < 2; i++)
1267                         tiledef_special[i].serialize(os, protocol_version);
1268                 writeU8(os, alpha);
1269                 writeU8(os, post_effect_color.getAlpha());
1270                 writeU8(os, post_effect_color.getRed());
1271                 writeU8(os, post_effect_color.getGreen());
1272                 writeU8(os, post_effect_color.getBlue());
1273                 writeU8(os, param_type);
1274                 writeU8(os, param_type_2);
1275                 writeU8(os, is_ground_content);
1276                 writeU8(os, light_propagates);
1277                 writeU8(os, sunlight_propagates);
1278                 writeU8(os, walkable);
1279                 writeU8(os, pointable);
1280                 writeU8(os, diggable);
1281                 writeU8(os, climbable);
1282                 writeU8(os, buildable_to);
1283                 os<<serializeString(""); // legacy: used to be metadata_name
1284                 writeU8(os, liquid_type);
1285                 os<<serializeString(liquid_alternative_flowing);
1286                 os<<serializeString(liquid_alternative_source);
1287                 writeU8(os, liquid_viscosity);
1288                 writeU8(os, light_source);
1289                 writeU32(os, damage_per_second);
1290                 node_box.serialize(os, protocol_version);
1291                 selection_box.serialize(os, protocol_version);
1292                 writeU8(os, legacy_facedir_simple);
1293                 writeU8(os, legacy_wallmounted);
1294                 serializeSimpleSoundSpec(sound_footstep, os);
1295                 serializeSimpleSoundSpec(sound_dig, os);
1296                 serializeSimpleSoundSpec(sound_dug, os);
1297         }
1298         else if (protocol_version > 13 && protocol_version < 24) {
1299                 writeU8(os, 6); // version
1300                 os<<serializeString(name);
1301                 writeU16(os, groups.size());
1302                 for (ItemGroupList::const_iterator
1303                         i = groups.begin(); i != groups.end(); ++i) {
1304                                 os<<serializeString(i->first);
1305                                 writeS16(os, i->second);
1306                 }
1307                 writeU8(os, drawtype);
1308                 writeF1000(os, visual_scale);
1309                 writeU8(os, 6);
1310                 for (u32 i = 0; i < 6; i++)
1311                         tiledef[i].serialize(os, protocol_version);
1312                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1313                 writeU8(os, 2);
1314                 for (u32 i = 0; i < 2; i++)
1315                         tiledef_special[i].serialize(os, protocol_version);
1316                 writeU8(os, alpha);
1317                 writeU8(os, post_effect_color.getAlpha());
1318                 writeU8(os, post_effect_color.getRed());
1319                 writeU8(os, post_effect_color.getGreen());
1320                 writeU8(os, post_effect_color.getBlue());
1321                 writeU8(os, param_type);
1322                 writeU8(os, param_type_2);
1323                 writeU8(os, is_ground_content);
1324                 writeU8(os, light_propagates);
1325                 writeU8(os, sunlight_propagates);
1326                 writeU8(os, walkable);
1327                 writeU8(os, pointable);
1328                 writeU8(os, diggable);
1329                 writeU8(os, climbable);
1330                 writeU8(os, buildable_to);
1331                 os<<serializeString(""); // legacy: used to be metadata_name
1332                 writeU8(os, liquid_type);
1333                 os<<serializeString(liquid_alternative_flowing);
1334                 os<<serializeString(liquid_alternative_source);
1335                 writeU8(os, liquid_viscosity);
1336                 writeU8(os, liquid_renewable);
1337                 writeU8(os, light_source);
1338                 writeU32(os, damage_per_second);
1339                 node_box.serialize(os, protocol_version);
1340                 selection_box.serialize(os, protocol_version);
1341                 writeU8(os, legacy_facedir_simple);
1342                 writeU8(os, legacy_wallmounted);
1343                 serializeSimpleSoundSpec(sound_footstep, os);
1344                 serializeSimpleSoundSpec(sound_dig, os);
1345                 serializeSimpleSoundSpec(sound_dug, os);
1346                 writeU8(os, rightclickable);
1347                 writeU8(os, drowning);
1348                 writeU8(os, leveled);
1349                 writeU8(os, liquid_range);
1350         } else
1351                 throw SerializationError("ContentFeatures::serialize(): "
1352                         "Unsupported version requested");
1353 }
1354
1355 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1356 {
1357         if (version == 5) // In PROTOCOL_VERSION 13
1358         {
1359                 name = deSerializeString(is);
1360                 groups.clear();
1361                 u32 groups_size = readU16(is);
1362                 for(u32 i=0; i<groups_size; i++){
1363                         std::string name = deSerializeString(is);
1364                         int value = readS16(is);
1365                         groups[name] = value;
1366                 }
1367                 drawtype = (enum NodeDrawType)readU8(is);
1368
1369                 visual_scale = readF1000(is);
1370                 if (readU8(is) != 6)
1371                         throw SerializationError("unsupported tile count");
1372                 for (u32 i = 0; i < 6; i++)
1373                         tiledef[i].deSerialize(is, version, drawtype);
1374                 if (readU8(is) != CF_SPECIAL_COUNT)
1375                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1376                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1377                         tiledef_special[i].deSerialize(is, version, drawtype);
1378                 alpha = readU8(is);
1379                 post_effect_color.setAlpha(readU8(is));
1380                 post_effect_color.setRed(readU8(is));
1381                 post_effect_color.setGreen(readU8(is));
1382                 post_effect_color.setBlue(readU8(is));
1383                 param_type = (enum ContentParamType)readU8(is);
1384                 param_type_2 = (enum ContentParamType2)readU8(is);
1385                 is_ground_content = readU8(is);
1386                 light_propagates = readU8(is);
1387                 sunlight_propagates = readU8(is);
1388                 walkable = readU8(is);
1389                 pointable = readU8(is);
1390                 diggable = readU8(is);
1391                 climbable = readU8(is);
1392                 buildable_to = readU8(is);
1393                 deSerializeString(is); // legacy: used to be metadata_name
1394                 liquid_type = (enum LiquidType)readU8(is);
1395                 liquid_alternative_flowing = deSerializeString(is);
1396                 liquid_alternative_source = deSerializeString(is);
1397                 liquid_viscosity = readU8(is);
1398                 light_source = readU8(is);
1399                 damage_per_second = readU32(is);
1400                 node_box.deSerialize(is);
1401                 selection_box.deSerialize(is);
1402                 legacy_facedir_simple = readU8(is);
1403                 legacy_wallmounted = readU8(is);
1404                 deSerializeSimpleSoundSpec(sound_footstep, is);
1405                 deSerializeSimpleSoundSpec(sound_dig, is);
1406                 deSerializeSimpleSoundSpec(sound_dug, is);
1407         } else if (version == 6) {
1408                 name = deSerializeString(is);
1409                 groups.clear();
1410                 u32 groups_size = readU16(is);
1411                 for (u32 i = 0; i < groups_size; i++) {
1412                         std::string name = deSerializeString(is);
1413                         int     value = readS16(is);
1414                         groups[name] = value;
1415                 }
1416                 drawtype = (enum NodeDrawType)readU8(is);
1417                 visual_scale = readF1000(is);
1418                 if (readU8(is) != 6)
1419                         throw SerializationError("unsupported tile count");
1420                 for (u32 i = 0; i < 6; i++)
1421                         tiledef[i].deSerialize(is, version, drawtype);
1422                 // CF_SPECIAL_COUNT in version 6 = 2
1423                 if (readU8(is) != 2)
1424                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1425                 for (u32 i = 0; i < 2; i++)
1426                         tiledef_special[i].deSerialize(is, version, drawtype);
1427                 alpha = readU8(is);
1428                 post_effect_color.setAlpha(readU8(is));
1429                 post_effect_color.setRed(readU8(is));
1430                 post_effect_color.setGreen(readU8(is));
1431                 post_effect_color.setBlue(readU8(is));
1432                 param_type = (enum ContentParamType)readU8(is);
1433                 param_type_2 = (enum ContentParamType2)readU8(is);
1434                 is_ground_content = readU8(is);
1435                 light_propagates = readU8(is);
1436                 sunlight_propagates = readU8(is);
1437                 walkable = readU8(is);
1438                 pointable = readU8(is);
1439                 diggable = readU8(is);
1440                 climbable = readU8(is);
1441                 buildable_to = readU8(is);
1442                 deSerializeString(is); // legacy: used to be metadata_name
1443                 liquid_type = (enum LiquidType)readU8(is);
1444                 liquid_alternative_flowing = deSerializeString(is);
1445                 liquid_alternative_source = deSerializeString(is);
1446                 liquid_viscosity = readU8(is);
1447                 liquid_renewable = readU8(is);
1448                 light_source = readU8(is);
1449                 damage_per_second = readU32(is);
1450                 node_box.deSerialize(is);
1451                 selection_box.deSerialize(is);
1452                 legacy_facedir_simple = readU8(is);
1453                 legacy_wallmounted = readU8(is);
1454                 deSerializeSimpleSoundSpec(sound_footstep, is);
1455                 deSerializeSimpleSoundSpec(sound_dig, is);
1456                 deSerializeSimpleSoundSpec(sound_dug, is);
1457                 rightclickable = readU8(is);
1458                 drowning = readU8(is);
1459                 leveled = readU8(is);
1460                 liquid_range = readU8(is);
1461         } else {
1462                 throw SerializationError("unsupported ContentFeatures version");
1463         }
1464 }
1465
1466
1467 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1468 {
1469         return m_node_registration_complete;
1470 }
1471
1472
1473 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1474 {
1475         m_node_registration_complete = completed;
1476 }
1477
1478
1479 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1480 {
1481         nr->m_ndef = this;
1482         if (m_node_registration_complete)
1483                 nr->nodeResolveInternal();
1484         else
1485                 m_pending_resolve_callbacks.push_back(nr);
1486 }
1487
1488
1489 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1490 {
1491         size_t len = m_pending_resolve_callbacks.size();
1492         for (size_t i = 0; i != len; i++) {
1493                 if (nr != m_pending_resolve_callbacks[i])
1494                         continue;
1495
1496                 len--;
1497                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1498                 m_pending_resolve_callbacks.resize(len);
1499                 return true;
1500         }
1501
1502         return false;
1503 }
1504
1505
1506 void CNodeDefManager::runNodeResolveCallbacks()
1507 {
1508         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1509                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1510                 nr->nodeResolveInternal();
1511         }
1512
1513         m_pending_resolve_callbacks.clear();
1514 }
1515
1516
1517 void CNodeDefManager::resetNodeResolveState()
1518 {
1519         m_node_registration_complete = false;
1520         m_pending_resolve_callbacks.clear();
1521 }
1522
1523 void CNodeDefManager::mapNodeboxConnections()
1524 {
1525         for (u32 i = 0; i < m_content_features.size(); i++) {
1526                 ContentFeatures *f = &m_content_features[i];
1527                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1528                         continue;
1529                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1530                                 it != f->connects_to.end(); ++it) {
1531                         getIds(*it, f->connects_to_ids);
1532                 }
1533         }
1534 }
1535
1536 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1537 {
1538         const ContentFeatures &f1 = get(from);
1539
1540         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1541                 return false;
1542
1543         // lookup target in connected set
1544         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1545                 return false;
1546
1547         const ContentFeatures &f2 = get(to);
1548
1549         if ((f2.drawtype == NDT_NODEBOX) && (f1.node_box.type == NODEBOX_CONNECTED))
1550                 // ignores actually looking if back connection exists
1551                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1552
1553         // does to node declare usable faces?
1554         if (f2.connect_sides > 0) {
1555                 if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
1556                         static const u8 rot[33 * 4] = {
1557                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1558                                 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
1559                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
1560                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1561                                 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
1562                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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                                 32, 16, 8, 4 // 32 - left
1566                         };
1567                         return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
1568                 }
1569                 return (f2.connect_sides & connect_face);
1570         }
1571         // the target is just a regular node, so connect no matter back connection
1572         return true;
1573 }
1574
1575 ////
1576 //// NodeResolver
1577 ////
1578
1579 NodeResolver::NodeResolver()
1580 {
1581         m_ndef            = NULL;
1582         m_nodenames_idx   = 0;
1583         m_nnlistsizes_idx = 0;
1584         m_resolve_done    = false;
1585
1586         m_nodenames.reserve(16);
1587         m_nnlistsizes.reserve(4);
1588 }
1589
1590
1591 NodeResolver::~NodeResolver()
1592 {
1593         if (!m_resolve_done && m_ndef)
1594                 m_ndef->cancelNodeResolveCallback(this);
1595 }
1596
1597
1598 void NodeResolver::nodeResolveInternal()
1599 {
1600         m_nodenames_idx   = 0;
1601         m_nnlistsizes_idx = 0;
1602
1603         resolveNodeNames();
1604         m_resolve_done = true;
1605
1606         m_nodenames.clear();
1607         m_nnlistsizes.clear();
1608 }
1609
1610
1611 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1612         const std::string &node_alt, content_t c_fallback)
1613 {
1614         if (m_nodenames_idx == m_nodenames.size()) {
1615                 *result_out = c_fallback;
1616                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1617                 return false;
1618         }
1619
1620         content_t c;
1621         std::string name = m_nodenames[m_nodenames_idx++];
1622
1623         bool success = m_ndef->getId(name, c);
1624         if (!success && node_alt != "") {
1625                 name = node_alt;
1626                 success = m_ndef->getId(name, c);
1627         }
1628
1629         if (!success) {
1630                 errorstream << "NodeResolver: failed to resolve node name '" << name
1631                         << "'." << std::endl;
1632                 c = c_fallback;
1633         }
1634
1635         *result_out = c;
1636         return success;
1637 }
1638
1639
1640 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1641         bool all_required, content_t c_fallback)
1642 {
1643         bool success = true;
1644
1645         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1646                 errorstream << "NodeResolver: no more node lists" << std::endl;
1647                 return false;
1648         }
1649
1650         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1651
1652         while (length--) {
1653                 if (m_nodenames_idx == m_nodenames.size()) {
1654                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1655                         return false;
1656                 }
1657
1658                 content_t c;
1659                 std::string &name = m_nodenames[m_nodenames_idx++];
1660
1661                 if (name.substr(0,6) != "group:") {
1662                         if (m_ndef->getId(name, c)) {
1663                                 result_out->push_back(c);
1664                         } else if (all_required) {
1665                                 errorstream << "NodeResolver: failed to resolve node name '"
1666                                         << name << "'." << std::endl;
1667                                 result_out->push_back(c_fallback);
1668                                 success = false;
1669                         }
1670                 } else {
1671                         std::set<content_t> cids;
1672                         std::set<content_t>::iterator it;
1673                         m_ndef->getIds(name, cids);
1674                         for (it = cids.begin(); it != cids.end(); ++it)
1675                                 result_out->push_back(*it);
1676                 }
1677         }
1678
1679         return success;
1680 }