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