Fix various points reported by cppcheck (#5656)
[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 "client.h"
27 #include <IMeshManipulator.h>
28 #endif
29 #include "log.h"
30 #include "settings.h"
31 #include "nameidmapping.h"
32 #include "util/numeric.h"
33 #include "util/serialize.h"
34 #include "exceptions.h"
35 #include "debug.h"
36 #include "gamedef.h"
37 #include "mapnode.h"
38 #include <fstream> // Used in applyTextureOverrides()
39
40 /*
41         NodeBox
42 */
43
44 void NodeBox::reset()
45 {
46         type = NODEBOX_REGULAR;
47         // default is empty
48         fixed.clear();
49         // default is sign/ladder-like
50         wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
51         wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
52         wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
53         // no default for other parts
54         connect_top.clear();
55         connect_bottom.clear();
56         connect_front.clear();
57         connect_left.clear();
58         connect_back.clear();
59         connect_right.clear();
60 }
61
62 void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
63 {
64         // Protocol >= 21
65         int version = 2;
66         if (protocol_version >= 27)
67                 version = 3;
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 >= 30)
192                 writeU8(os, 4);
193         else if (protocol_version >= 29)
194                 writeU8(os, 3);
195         else if (protocol_version >= 26)
196                 writeU8(os, 2);
197         else
198                 writeU8(os, 1);
199
200         os << serializeString(name);
201         animation.serialize(os, protocol_version);
202         writeU8(os, backface_culling);
203         if (protocol_version >= 26) {
204                 writeU8(os, tileable_horizontal);
205                 writeU8(os, tileable_vertical);
206         }
207         if (protocol_version >= 30) {
208                 writeU8(os, has_color);
209                 if (has_color) {
210                         writeU8(os, color.getRed());
211                         writeU8(os, color.getGreen());
212                         writeU8(os, color.getBlue());
213                 }
214         }
215 }
216
217 void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
218 {
219         int version = readU8(is);
220         name = deSerializeString(is);
221         animation.deSerialize(is, version >= 3 ? 29 : 26);
222         if (version >= 1)
223                 backface_culling = readU8(is);
224         if (version >= 2) {
225                 tileable_horizontal = readU8(is);
226                 tileable_vertical = readU8(is);
227         }
228         if (version >= 4) {
229                 has_color = readU8(is);
230                 if (has_color) {
231                         color.setRed(readU8(is));
232                         color.setGreen(readU8(is));
233                         color.setBlue(readU8(is));
234                 }
235         }
236
237         if ((contenfeatures_version < 8) &&
238                 ((drawtype == NDT_MESH) ||
239                  (drawtype == NDT_FIRELIKE) ||
240                  (drawtype == NDT_LIQUID) ||
241                  (drawtype == NDT_PLANTLIKE)))
242                 backface_culling = false;
243 }
244
245
246 /*
247         SimpleSoundSpec serialization
248 */
249
250 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
251                 std::ostream &os)
252 {
253         os<<serializeString(ss.name);
254         writeF1000(os, ss.gain);
255 }
256 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
257 {
258         ss.name = deSerializeString(is);
259         ss.gain = readF1000(is);
260 }
261
262 void TextureSettings::readSettings()
263 {
264         connected_glass                = g_settings->getBool("connected_glass");
265         opaque_water                   = g_settings->getBool("opaque_water");
266         bool enable_shaders            = g_settings->getBool("enable_shaders");
267         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
268         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
269         bool smooth_lighting           = g_settings->getBool("smooth_lighting");
270         enable_mesh_cache              = g_settings->getBool("enable_mesh_cache");
271         enable_minimap                 = g_settings->getBool("enable_minimap");
272         std::string leaves_style_str   = g_settings->get("leaves_style");
273
274         // Mesh cache is not supported in combination with smooth lighting
275         if (smooth_lighting)
276                 enable_mesh_cache = false;
277
278         use_normal_texture = enable_shaders &&
279                 (enable_bumpmapping || enable_parallax_occlusion);
280         if (leaves_style_str == "fancy") {
281                 leaves_style = LEAVES_FANCY;
282         } else if (leaves_style_str == "simple") {
283                 leaves_style = LEAVES_SIMPLE;
284         } else {
285                 leaves_style = LEAVES_OPAQUE;
286         }
287 }
288
289 /*
290         ContentFeatures
291 */
292
293 ContentFeatures::ContentFeatures()
294 {
295         reset();
296 }
297
298 ContentFeatures::~ContentFeatures()
299 {
300 }
301
302 void ContentFeatures::reset()
303 {
304         /*
305                 Cached stuff
306         */
307 #ifndef SERVER
308         solidness = 2;
309         visual_solidness = 0;
310         backface_culling = true;
311
312 #endif
313         has_on_construct = false;
314         has_on_destruct = false;
315         has_after_destruct = false;
316         /*
317                 Actual data
318
319                 NOTE: Most of this is always overridden by the default values given
320                       in builtin.lua
321         */
322         name = "";
323         groups.clear();
324         // Unknown nodes can be dug
325         groups["dig_immediate"] = 2;
326         drawtype = NDT_NORMAL;
327         mesh = "";
328 #ifndef SERVER
329         for(u32 i = 0; i < 24; i++)
330                 mesh_ptr[i] = NULL;
331         minimap_color = video::SColor(0, 0, 0, 0);
332 #endif
333         visual_scale = 1.0;
334         for(u32 i = 0; i < 6; i++)
335                 tiledef[i] = TileDef();
336         for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
337                 tiledef_special[j] = TileDef();
338         alpha = 255;
339         post_effect_color = video::SColor(0, 0, 0, 0);
340         param_type = CPT_NONE;
341         param_type_2 = CPT2_NONE;
342         is_ground_content = false;
343         light_propagates = false;
344         sunlight_propagates = false;
345         walkable = true;
346         pointable = true;
347         diggable = true;
348         climbable = false;
349         buildable_to = false;
350         floodable = false;
351         rightclickable = true;
352         leveled = 0;
353         liquid_type = LIQUID_NONE;
354         liquid_alternative_flowing = "";
355         liquid_alternative_source = "";
356         liquid_viscosity = 0;
357         liquid_renewable = true;
358         liquid_range = LIQUID_LEVEL_MAX+1;
359         drowning = 0;
360         light_source = 0;
361         damage_per_second = 0;
362         node_box = NodeBox();
363         selection_box = NodeBox();
364         collision_box = NodeBox();
365         waving = 0;
366         legacy_facedir_simple = false;
367         legacy_wallmounted = false;
368         sound_footstep = SimpleSoundSpec();
369         sound_dig = SimpleSoundSpec("__group");
370         sound_dug = SimpleSoundSpec();
371         connects_to.clear();
372         connects_to_ids.clear();
373         connect_sides = 0;
374         color = video::SColor(0xFFFFFFFF);
375         palette_name = "";
376         palette = NULL;
377 }
378
379 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
380 {
381         if (protocol_version < 31) {
382                 serializeOld(os, protocol_version);
383                 return;
384         }
385
386         // version
387         writeU8(os, 10);
388
389         // general
390         os << serializeString(name);
391         writeU16(os, groups.size());
392         for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
393                 ++i) {
394                 os << serializeString(i->first);
395                 writeS16(os, i->second);
396         }
397         writeU8(os, param_type);
398         writeU8(os, param_type_2);
399
400         // visual
401         writeU8(os, drawtype);
402         os << serializeString(mesh);
403         writeF1000(os, visual_scale);
404         writeU8(os, 6);
405         for (u32 i = 0; i < 6; i++)
406                 tiledef[i].serialize(os, protocol_version);
407         for (u32 i = 0; i < 6; i++)
408                 tiledef_overlay[i].serialize(os, protocol_version);
409         writeU8(os, CF_SPECIAL_COUNT);
410         for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
411                 tiledef_special[i].serialize(os, protocol_version);
412         }
413         writeU8(os, alpha);
414         writeU8(os, color.getRed());
415         writeU8(os, color.getGreen());
416         writeU8(os, color.getBlue());
417         os << serializeString(palette_name);
418         writeU8(os, waving);
419         writeU8(os, connect_sides);
420         writeU16(os, connects_to_ids.size());
421         for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
422                 i != connects_to_ids.end(); ++i)
423                 writeU16(os, *i);
424         writeU8(os, post_effect_color.getAlpha());
425         writeU8(os, post_effect_color.getRed());
426         writeU8(os, post_effect_color.getGreen());
427         writeU8(os, post_effect_color.getBlue());
428         writeU8(os, leveled);
429
430         // lighting
431         writeU8(os, light_propagates);
432         writeU8(os, sunlight_propagates);
433         writeU8(os, light_source);
434
435         // map generation
436         writeU8(os, is_ground_content);
437
438         // interaction
439         writeU8(os, walkable);
440         writeU8(os, pointable);
441         writeU8(os, diggable);
442         writeU8(os, climbable);
443         writeU8(os, buildable_to);
444         writeU8(os, rightclickable);
445         writeU32(os, damage_per_second);
446
447         // liquid
448         writeU8(os, liquid_type);
449         os << serializeString(liquid_alternative_flowing);
450         os << serializeString(liquid_alternative_source);
451         writeU8(os, liquid_viscosity);
452         writeU8(os, liquid_renewable);
453         writeU8(os, liquid_range);
454         writeU8(os, drowning);
455         writeU8(os, floodable);
456
457         // node boxes
458         node_box.serialize(os, protocol_version);
459         selection_box.serialize(os, protocol_version);
460         collision_box.serialize(os, protocol_version);
461
462         // sound
463         serializeSimpleSoundSpec(sound_footstep, os);
464         serializeSimpleSoundSpec(sound_dig, os);
465         serializeSimpleSoundSpec(sound_dug, os);
466
467         // legacy
468         writeU8(os, legacy_facedir_simple);
469         writeU8(os, legacy_wallmounted);
470 }
471
472 void ContentFeatures::correctAlpha()
473 {
474         if (alpha == 0 || alpha == 255)
475                 return;
476
477         for (u32 i = 0; i < 6; i++) {
478                 std::stringstream s;
479                 s << tiledef[i].name << "^[noalpha^[opacity:" << ((int)alpha);
480                 tiledef[i].name = s.str();
481         }
482
483         for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
484                 std::stringstream s;
485                 s << tiledef_special[i].name << "^[noalpha^[opacity:" << ((int)alpha);
486                 tiledef_special[i].name = s.str();
487         }
488 }
489
490 void ContentFeatures::deSerialize(std::istream &is)
491 {
492         // version detection
493         int version = readU8(is);
494         if (version < 9) {
495                 deSerializeOld(is, version);
496                 return;
497         } else if (version > 10) {
498                 throw SerializationError("unsupported ContentFeatures version");
499         }
500
501         // general
502         name = deSerializeString(is);
503         groups.clear();
504         u32 groups_size = readU16(is);
505         for (u32 i = 0; i < groups_size; i++) {
506                 std::string name = deSerializeString(is);
507                 int value = readS16(is);
508                 groups[name] = value;
509         }
510         param_type = (enum ContentParamType) readU8(is);
511         param_type_2 = (enum ContentParamType2) readU8(is);
512
513         // visual
514         drawtype = (enum NodeDrawType) readU8(is);
515         mesh = deSerializeString(is);
516         visual_scale = readF1000(is);
517         if (readU8(is) != 6)
518                 throw SerializationError("unsupported tile count");
519         for (u32 i = 0; i < 6; i++)
520                 tiledef[i].deSerialize(is, version, drawtype);
521         if (version >= 10)
522                 for (u32 i = 0; i < 6; i++)
523                         tiledef_overlay[i].deSerialize(is, version, drawtype);
524         if (readU8(is) != CF_SPECIAL_COUNT)
525                 throw SerializationError("unsupported CF_SPECIAL_COUNT");
526         for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
527                 tiledef_special[i].deSerialize(is, version, drawtype);
528         alpha = readU8(is);
529         color.setRed(readU8(is));
530         color.setGreen(readU8(is));
531         color.setBlue(readU8(is));
532         palette_name = deSerializeString(is);
533         waving = readU8(is);
534         connect_sides = readU8(is);
535         u16 connects_to_size = readU16(is);
536         connects_to_ids.clear();
537         for (u16 i = 0; i < connects_to_size; i++)
538                 connects_to_ids.insert(readU16(is));
539         post_effect_color.setAlpha(readU8(is));
540         post_effect_color.setRed(readU8(is));
541         post_effect_color.setGreen(readU8(is));
542         post_effect_color.setBlue(readU8(is));
543         leveled = readU8(is);
544
545         // lighting-related
546         light_propagates = readU8(is);
547         sunlight_propagates = readU8(is);
548         light_source = readU8(is);
549         light_source = MYMIN(light_source, LIGHT_MAX);
550
551         // map generation
552         is_ground_content = readU8(is);
553
554         // interaction
555         walkable = readU8(is);
556         pointable = readU8(is);
557         diggable = readU8(is);
558         climbable = readU8(is);
559         buildable_to = readU8(is);
560         rightclickable = readU8(is);
561         damage_per_second = readU32(is);
562
563         // liquid
564         liquid_type = (enum LiquidType) readU8(is);
565         liquid_alternative_flowing = deSerializeString(is);
566         liquid_alternative_source = deSerializeString(is);
567         liquid_viscosity = readU8(is);
568         liquid_renewable = readU8(is);
569         liquid_range = readU8(is);
570         drowning = readU8(is);
571         floodable = readU8(is);
572
573         // node boxes
574         node_box.deSerialize(is);
575         selection_box.deSerialize(is);
576         collision_box.deSerialize(is);
577
578         // sounds
579         deSerializeSimpleSoundSpec(sound_footstep, is);
580         deSerializeSimpleSoundSpec(sound_dig, is);
581         deSerializeSimpleSoundSpec(sound_dug, is);
582
583         // read legacy properties
584         legacy_facedir_simple = readU8(is);
585         legacy_wallmounted = readU8(is);
586 }
587
588 #ifndef SERVER
589 void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *tile,
590                 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
591                 bool backface_culling, u8 material_type)
592 {
593         tile->shader_id     = shader_id;
594         tile->texture       = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
595         tile->material_type = material_type;
596
597         // Normal texture and shader flags texture
598         if (use_normal_texture) {
599                 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
600         }
601         tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
602
603         // Material flags
604         tile->material_flags = 0;
605         if (backface_culling)
606                 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
607         if (tiledef->animation.type != TAT_NONE)
608                 tile->material_flags |= MATERIAL_FLAG_ANIMATION;
609         if (tiledef->tileable_horizontal)
610                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
611         if (tiledef->tileable_vertical)
612                 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
613
614         // Color
615         tile->has_color = tiledef->has_color;
616         if (tiledef->has_color)
617                 tile->color = tiledef->color;
618         else
619                 tile->color = color;
620
621         // Animation parameters
622         int frame_count = 1;
623         if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
624                 int frame_length_ms;
625                 tiledef->animation.determineParams(tile->texture->getOriginalSize(),
626                                 &frame_count, &frame_length_ms, NULL);
627                 tile->animation_frame_count = frame_count;
628                 tile->animation_frame_length_ms = frame_length_ms;
629         }
630
631         if (frame_count == 1) {
632                 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
633         } else {
634                 std::ostringstream os(std::ios::binary);
635                 tile->frames.resize(frame_count);
636
637                 for (int i = 0; i < frame_count; i++) {
638
639                         FrameSpec frame;
640
641                         os.str("");
642                         os << tiledef->name;
643                         tiledef->animation.getTextureModifer(os,
644                                         tile->texture->getOriginalSize(), i);
645
646                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
647                         if (tile->normal_texture)
648                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
649                         frame.flags_texture = tile->flags_texture;
650                         tile->frames[i] = frame;
651                 }
652         }
653 }
654 #endif
655
656 #ifndef SERVER
657 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
658         scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
659 {
660         // minimap pixel color - the average color of a texture
661         if (tsettings.enable_minimap && tiledef[0].name != "")
662                 minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
663
664         // Figure out the actual tiles to use
665         TileDef tdef[6];
666         for (u32 j = 0; j < 6; j++) {
667                 tdef[j] = tiledef[j];
668                 if (tdef[j].name == "")
669                         tdef[j].name = "unknown_node.png";
670         }
671
672         bool is_liquid = false;
673         bool is_water_surface = false;
674
675         u8 material_type = (alpha == 255) ?
676                 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
677
678         switch (drawtype) {
679         default:
680         case NDT_NORMAL:
681                 solidness = 2;
682                 break;
683         case NDT_AIRLIKE:
684                 solidness = 0;
685                 break;
686         case NDT_LIQUID:
687                 assert(liquid_type == LIQUID_SOURCE);
688                 if (tsettings.opaque_water)
689                         alpha = 255;
690                 solidness = 1;
691                 is_liquid = true;
692                 break;
693         case NDT_FLOWINGLIQUID:
694                 assert(liquid_type == LIQUID_FLOWING);
695                 solidness = 0;
696                 if (tsettings.opaque_water)
697                         alpha = 255;
698                 is_liquid = true;
699                 break;
700         case NDT_GLASSLIKE:
701                 solidness = 0;
702                 visual_solidness = 1;
703                 break;
704         case NDT_GLASSLIKE_FRAMED:
705                 solidness = 0;
706                 visual_solidness = 1;
707                 break;
708         case NDT_GLASSLIKE_FRAMED_OPTIONAL:
709                 solidness = 0;
710                 visual_solidness = 1;
711                 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
712                 break;
713         case NDT_ALLFACES:
714                 solidness = 0;
715                 visual_solidness = 1;
716                 break;
717         case NDT_ALLFACES_OPTIONAL:
718                 if (tsettings.leaves_style == LEAVES_FANCY) {
719                         drawtype = NDT_ALLFACES;
720                         solidness = 0;
721                         visual_solidness = 1;
722                 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
723                         for (u32 j = 0; j < 6; j++) {
724                                 if (tiledef_special[j].name != "")
725                                         tdef[j].name = tiledef_special[j].name;
726                         }
727                         drawtype = NDT_GLASSLIKE;
728                         solidness = 0;
729                         visual_solidness = 1;
730                 } else {
731                         drawtype = NDT_NORMAL;
732                         solidness = 2;
733                         for (u32 i = 0; i < 6; i++)
734                                 tdef[i].name += std::string("^[noalpha");
735                 }
736                 if (waving == 1)
737                         material_type = TILE_MATERIAL_WAVING_LEAVES;
738                 break;
739         case NDT_PLANTLIKE:
740                 solidness = 0;
741                 if (waving == 1)
742                         material_type = TILE_MATERIAL_WAVING_PLANTS;
743                 break;
744         case NDT_FIRELIKE:
745                 solidness = 0;
746                 break;
747         case NDT_MESH:
748                 solidness = 0;
749                 break;
750         case NDT_TORCHLIKE:
751         case NDT_SIGNLIKE:
752         case NDT_FENCELIKE:
753         case NDT_RAILLIKE:
754         case NDT_NODEBOX:
755                 solidness = 0;
756                 break;
757         }
758
759         if (is_liquid) {
760                 material_type = (alpha == 255) ?
761                         TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
762                 if (name == "default:water_source")
763                         is_water_surface = true;
764         }
765
766         // Vertex alpha is no longer supported, correct if necessary.
767         correctAlpha();
768
769         u32 tile_shader[6];
770         for (u16 j = 0; j < 6; j++) {
771                 tile_shader[j] = shdsrc->getShader("nodes_shader",
772                         material_type, drawtype);
773         }
774
775         if (is_water_surface) {
776                 tile_shader[0] = shdsrc->getShader("water_surface_shader",
777                         material_type, drawtype);
778         }
779
780         // Tiles (fill in f->tiles[])
781         for (u16 j = 0; j < 6; j++) {
782                 fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
783                         tsettings.use_normal_texture,
784                         tiledef[j].backface_culling, material_type);
785                 if (tiledef_overlay[j].name!="")
786                         fillTileAttribs(tsrc, &tiles[j].layers[1], &tiledef_overlay[j],
787                                 tile_shader[j], tsettings.use_normal_texture,
788                                 tiledef[j].backface_culling, material_type);
789         }
790
791         // Special tiles (fill in f->special_tiles[])
792         for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
793                 fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tiledef_special[j],
794                         tile_shader[j], tsettings.use_normal_texture,
795                         tiledef_special[j].backface_culling, material_type);
796         }
797
798         if (param_type_2 == CPT2_COLOR ||
799                         param_type_2 == CPT2_COLORED_FACEDIR ||
800                         param_type_2 == CPT2_COLORED_WALLMOUNTED)
801                 palette = tsrc->getPalette(palette_name);
802
803         if ((drawtype == NDT_MESH) && (mesh != "")) {
804                 // Meshnode drawtype
805                 // Read the mesh and apply scale
806                 mesh_ptr[0] = client->getMesh(mesh);
807                 if (mesh_ptr[0]){
808                         v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
809                         scaleMesh(mesh_ptr[0], scale);
810                         recalculateBoundingBox(mesh_ptr[0]);
811                         meshmanip->recalculateNormals(mesh_ptr[0], true, false);
812                 }
813         } else if ((drawtype == NDT_NODEBOX) &&
814                         ((node_box.type == NODEBOX_REGULAR) ||
815                         (node_box.type == NODEBOX_FIXED)) &&
816                         (!node_box.fixed.empty())) {
817                 //Convert regular nodebox nodes to meshnodes
818                 //Change the drawtype and apply scale
819                 drawtype = NDT_MESH;
820                 mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
821                 v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
822                 scaleMesh(mesh_ptr[0], scale);
823                 recalculateBoundingBox(mesh_ptr[0]);
824                 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
825         }
826
827         //Cache 6dfacedir and wallmounted rotated clones of meshes
828         if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
829                         (param_type_2 == CPT2_FACEDIR
830                         || param_type_2 == CPT2_COLORED_FACEDIR)) {
831                 for (u16 j = 1; j < 24; j++) {
832                         mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
833                         rotateMeshBy6dFacedir(mesh_ptr[j], j);
834                         recalculateBoundingBox(mesh_ptr[j]);
835                         meshmanip->recalculateNormals(mesh_ptr[j], true, false);
836                 }
837         } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
838                         && (param_type_2 == CPT2_WALLMOUNTED ||
839                         param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
840                 static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
841                 for (u16 j = 1; j < 6; j++) {
842                         mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
843                         rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
844                         recalculateBoundingBox(mesh_ptr[j]);
845                         meshmanip->recalculateNormals(mesh_ptr[j], true, false);
846                 }
847                 rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
848                 recalculateBoundingBox(mesh_ptr[0]);
849                 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
850         }
851 }
852 #endif
853
854 /*
855         CNodeDefManager
856 */
857
858 class CNodeDefManager: public IWritableNodeDefManager {
859 public:
860         CNodeDefManager();
861         virtual ~CNodeDefManager();
862         void clear();
863         virtual IWritableNodeDefManager *clone();
864         inline virtual const ContentFeatures& get(content_t c) const;
865         inline virtual const ContentFeatures& get(const MapNode &n) const;
866         virtual bool getId(const std::string &name, content_t &result) const;
867         virtual content_t getId(const std::string &name) const;
868         virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
869         virtual const ContentFeatures& get(const std::string &name) const;
870         content_t allocateId();
871         virtual content_t set(const std::string &name, const ContentFeatures &def);
872         virtual content_t allocateDummy(const std::string &name);
873         virtual void removeNode(const std::string &name);
874         virtual void updateAliases(IItemDefManager *idef);
875         virtual void applyTextureOverrides(const std::string &override_filepath);
876         virtual void updateTextures(IGameDef *gamedef,
877                 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
878                 void *progress_cbk_args);
879         void serialize(std::ostream &os, u16 protocol_version) const;
880         void deSerialize(std::istream &is);
881
882         inline virtual bool getNodeRegistrationStatus() const;
883         inline virtual void setNodeRegistrationStatus(bool completed);
884
885         virtual void pendNodeResolve(NodeResolver *nr);
886         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
887         virtual void runNodeResolveCallbacks();
888         virtual void resetNodeResolveState();
889         virtual void mapNodeboxConnections();
890         virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
891         virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
892         {
893                 return m_selection_box_int_union;
894         }
895
896 private:
897         void addNameIdMapping(content_t i, std::string name);
898         /*!
899          * Recalculates m_selection_box_int_union based on
900          * m_selection_box_union.
901          */
902         void fixSelectionBoxIntUnion();
903
904         // Features indexed by id
905         std::vector<ContentFeatures> m_content_features;
906
907         // A mapping for fast converting back and forth between names and ids
908         NameIdMapping m_name_id_mapping;
909
910         // Like m_name_id_mapping, but only from names to ids, and includes
911         // item aliases too. Updated by updateAliases()
912         // Note: Not serialized.
913
914         UNORDERED_MAP<std::string, content_t> m_name_id_mapping_with_aliases;
915
916         // A mapping from groups to a list of content_ts (and their levels)
917         // that belong to it.  Necessary for a direct lookup in getIds().
918         // Note: Not serialized.
919         UNORDERED_MAP<std::string, GroupItems> m_group_to_items;
920
921         // Next possibly free id
922         content_t m_next_id;
923
924         // NodeResolvers to callback once node registration has ended
925         std::vector<NodeResolver *> m_pending_resolve_callbacks;
926
927         // True when all nodes have been registered
928         bool m_node_registration_complete;
929
930         //! The union of all nodes' selection boxes.
931         aabb3f m_selection_box_union;
932         /*!
933          * The smallest box in node coordinates that
934          * contains all nodes' selection boxes.
935          */
936         core::aabbox3d<s16> m_selection_box_int_union;
937 };
938
939
940 CNodeDefManager::CNodeDefManager()
941 {
942         clear();
943 }
944
945
946 CNodeDefManager::~CNodeDefManager()
947 {
948 #ifndef SERVER
949         for (u32 i = 0; i < m_content_features.size(); i++) {
950                 ContentFeatures *f = &m_content_features[i];
951                 for (u32 j = 0; j < 24; j++) {
952                         if (f->mesh_ptr[j])
953                                 f->mesh_ptr[j]->drop();
954                 }
955         }
956 #endif
957 }
958
959
960 void CNodeDefManager::clear()
961 {
962         m_content_features.clear();
963         m_name_id_mapping.clear();
964         m_name_id_mapping_with_aliases.clear();
965         m_group_to_items.clear();
966         m_next_id = 0;
967         m_selection_box_union.reset(0,0,0);
968         m_selection_box_int_union.reset(0,0,0);
969
970         resetNodeResolveState();
971
972         u32 initial_length = 0;
973         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
974         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
975         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
976         m_content_features.resize(initial_length);
977
978         // Set CONTENT_UNKNOWN
979         {
980                 ContentFeatures f;
981                 f.name = "unknown";
982                 // Insert directly into containers
983                 content_t c = CONTENT_UNKNOWN;
984                 m_content_features[c] = f;
985                 addNameIdMapping(c, f.name);
986         }
987
988         // Set CONTENT_AIR
989         {
990                 ContentFeatures f;
991                 f.name                = "air";
992                 f.drawtype            = NDT_AIRLIKE;
993                 f.param_type          = CPT_LIGHT;
994                 f.light_propagates    = true;
995                 f.sunlight_propagates = true;
996                 f.walkable            = false;
997                 f.pointable           = false;
998                 f.diggable            = false;
999                 f.buildable_to        = true;
1000                 f.floodable           = true;
1001                 f.is_ground_content   = true;
1002                 // Insert directly into containers
1003                 content_t c = CONTENT_AIR;
1004                 m_content_features[c] = f;
1005                 addNameIdMapping(c, f.name);
1006         }
1007
1008         // Set CONTENT_IGNORE
1009         {
1010                 ContentFeatures f;
1011                 f.name                = "ignore";
1012                 f.drawtype            = NDT_AIRLIKE;
1013                 f.param_type          = CPT_NONE;
1014                 f.light_propagates    = false;
1015                 f.sunlight_propagates = false;
1016                 f.walkable            = false;
1017                 f.pointable           = false;
1018                 f.diggable            = false;
1019                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
1020                 f.is_ground_content   = true;
1021                 // Insert directly into containers
1022                 content_t c = CONTENT_IGNORE;
1023                 m_content_features[c] = f;
1024                 addNameIdMapping(c, f.name);
1025         }
1026 }
1027
1028
1029 IWritableNodeDefManager *CNodeDefManager::clone()
1030 {
1031         CNodeDefManager *mgr = new CNodeDefManager();
1032         *mgr = *this;
1033         return mgr;
1034 }
1035
1036
1037 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1038 {
1039         return c < m_content_features.size()
1040                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1041 }
1042
1043
1044 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1045 {
1046         return get(n.getContent());
1047 }
1048
1049
1050 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1051 {
1052         UNORDERED_MAP<std::string, content_t>::const_iterator
1053                 i = m_name_id_mapping_with_aliases.find(name);
1054         if(i == m_name_id_mapping_with_aliases.end())
1055                 return false;
1056         result = i->second;
1057         return true;
1058 }
1059
1060
1061 content_t CNodeDefManager::getId(const std::string &name) const
1062 {
1063         content_t id = CONTENT_IGNORE;
1064         getId(name, id);
1065         return id;
1066 }
1067
1068
1069 bool CNodeDefManager::getIds(const std::string &name,
1070                 std::set<content_t> &result) const
1071 {
1072         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1073         if (name.substr(0,6) != "group:") {
1074                 content_t id = CONTENT_IGNORE;
1075                 bool exists = getId(name, id);
1076                 if (exists)
1077                         result.insert(id);
1078                 return exists;
1079         }
1080         std::string group = name.substr(6);
1081
1082         UNORDERED_MAP<std::string, GroupItems>::const_iterator
1083                 i = m_group_to_items.find(group);
1084         if (i == m_group_to_items.end())
1085                 return true;
1086
1087         const GroupItems &items = i->second;
1088         for (GroupItems::const_iterator j = items.begin();
1089                 j != items.end(); ++j) {
1090                 if ((*j).second != 0)
1091                         result.insert((*j).first);
1092         }
1093         //printf("getIds: %dus\n", t.stop());
1094         return true;
1095 }
1096
1097
1098 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1099 {
1100         content_t id = CONTENT_UNKNOWN;
1101         getId(name, id);
1102         return get(id);
1103 }
1104
1105
1106 // returns CONTENT_IGNORE if no free ID found
1107 content_t CNodeDefManager::allocateId()
1108 {
1109         for (content_t id = m_next_id;
1110                         id >= m_next_id; // overflow?
1111                         ++id) {
1112                 while (id >= m_content_features.size()) {
1113                         m_content_features.push_back(ContentFeatures());
1114                 }
1115                 const ContentFeatures &f = m_content_features[id];
1116                 if (f.name == "") {
1117                         m_next_id = id + 1;
1118                         return id;
1119                 }
1120         }
1121         // If we arrive here, an overflow occurred in id.
1122         // That means no ID was found
1123         return CONTENT_IGNORE;
1124 }
1125
1126
1127 /*!
1128  * Returns the smallest box that contains all boxes
1129  * in the vector. Box_union is expanded.
1130  * @param[in]      boxes     the vector containing the boxes
1131  * @param[in, out] box_union the union of the arguments
1132  */
1133 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1134 {
1135         for (std::vector<aabb3f>::const_iterator it = boxes.begin();
1136                         it != boxes.end(); ++it) {
1137                 box_union->addInternalBox(*it);
1138         }
1139 }
1140
1141
1142 /*!
1143  * Returns a box that contains the nodebox in every case.
1144  * The argument node_union is expanded.
1145  * @param[in]      nodebox  the nodebox to be measured
1146  * @param[in]      features  used to decide whether the nodebox
1147  * can be rotated
1148  * @param[in, out] box_union the union of the arguments
1149  */
1150 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1151         aabb3f *box_union)
1152 {
1153         switch(nodebox.type) {
1154                 case NODEBOX_FIXED:
1155                 case NODEBOX_LEVELED: {
1156                         // Raw union
1157                         aabb3f half_processed(0, 0, 0, 0, 0, 0);
1158                         boxVectorUnion(nodebox.fixed, &half_processed);
1159                         // Set leveled boxes to maximal
1160                         if (nodebox.type == NODEBOX_LEVELED) {
1161                                 half_processed.MaxEdge.Y = +BS / 2;
1162                         }
1163                         if (features.param_type_2 == CPT2_FACEDIR ||
1164                                         features.param_type_2 == CPT2_COLORED_FACEDIR) {
1165                                 // Get maximal coordinate
1166                                 f32 coords[] = {
1167                                         fabsf(half_processed.MinEdge.X),
1168                                         fabsf(half_processed.MinEdge.Y),
1169                                         fabsf(half_processed.MinEdge.Z),
1170                                         fabsf(half_processed.MaxEdge.X),
1171                                         fabsf(half_processed.MaxEdge.Y),
1172                                         fabsf(half_processed.MaxEdge.Z) };
1173                                 f32 max = 0;
1174                                 for (int i = 0; i < 6; i++) {
1175                                         if (max < coords[i]) {
1176                                                 max = coords[i];
1177                                         }
1178                                 }
1179                                 // Add the union of all possible rotated boxes
1180                                 box_union->addInternalPoint(-max, -max, -max);
1181                                 box_union->addInternalPoint(+max, +max, +max);
1182                         } else {
1183                                 box_union->addInternalBox(half_processed);
1184                         }
1185                         break;
1186                 }
1187                 case NODEBOX_WALLMOUNTED: {
1188                         // Add fix boxes
1189                         box_union->addInternalBox(nodebox.wall_top);
1190                         box_union->addInternalBox(nodebox.wall_bottom);
1191                         // Find maximal coordinate in the X-Z plane
1192                         f32 coords[] = {
1193                                 fabsf(nodebox.wall_side.MinEdge.X),
1194                                 fabsf(nodebox.wall_side.MinEdge.Z),
1195                                 fabsf(nodebox.wall_side.MaxEdge.X),
1196                                 fabsf(nodebox.wall_side.MaxEdge.Z) };
1197                         f32 max = 0;
1198                         for (int i = 0; i < 4; i++) {
1199                                 if (max < coords[i]) {
1200                                         max = coords[i];
1201                                 }
1202                         }
1203                         // Add the union of all possible rotated boxes
1204                         box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1205                         box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1206                         break;
1207                 }
1208                 case NODEBOX_CONNECTED: {
1209                         // Add all possible connected boxes
1210                         boxVectorUnion(nodebox.fixed,          box_union);
1211                         boxVectorUnion(nodebox.connect_top,    box_union);
1212                         boxVectorUnion(nodebox.connect_bottom, box_union);
1213                         boxVectorUnion(nodebox.connect_front,  box_union);
1214                         boxVectorUnion(nodebox.connect_left,   box_union);
1215                         boxVectorUnion(nodebox.connect_back,   box_union);
1216                         boxVectorUnion(nodebox.connect_right,  box_union);
1217                         break;
1218                 }
1219                 default: {
1220                         // NODEBOX_REGULAR
1221                         box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1222                         box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1223                 }
1224         }
1225 }
1226
1227
1228 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1229 {
1230         m_selection_box_int_union.MinEdge.X = floorf(
1231                 m_selection_box_union.MinEdge.X / BS + 0.5f);
1232         m_selection_box_int_union.MinEdge.Y = floorf(
1233                 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1234         m_selection_box_int_union.MinEdge.Z = floorf(
1235                 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1236         m_selection_box_int_union.MaxEdge.X = ceilf(
1237                 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1238         m_selection_box_int_union.MaxEdge.Y = ceilf(
1239                 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1240         m_selection_box_int_union.MaxEdge.Z = ceilf(
1241                 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1242 }
1243
1244
1245 // IWritableNodeDefManager
1246 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1247 {
1248         // Pre-conditions
1249         assert(name != "");
1250         assert(name == def.name);
1251
1252         // Don't allow redefining ignore (but allow air and unknown)
1253         if (name == "ignore") {
1254                 warningstream << "NodeDefManager: Ignoring "
1255                         "CONTENT_IGNORE redefinition"<<std::endl;
1256                 return CONTENT_IGNORE;
1257         }
1258
1259         content_t id = CONTENT_IGNORE;
1260         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1261                 // Get new id
1262                 id = allocateId();
1263                 if (id == CONTENT_IGNORE) {
1264                         warningstream << "NodeDefManager: Absolute "
1265                                 "limit reached" << std::endl;
1266                         return CONTENT_IGNORE;
1267                 }
1268                 assert(id != CONTENT_IGNORE);
1269                 addNameIdMapping(id, name);
1270         }
1271         m_content_features[id] = def;
1272         verbosestream << "NodeDefManager: registering content id \"" << id
1273                 << "\": name=\"" << def.name << "\""<<std::endl;
1274
1275         getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1276         fixSelectionBoxIntUnion();
1277         // Add this content to the list of all groups it belongs to
1278         // FIXME: This should remove a node from groups it no longer
1279         // belongs to when a node is re-registered
1280         for (ItemGroupList::const_iterator i = def.groups.begin();
1281                 i != def.groups.end(); ++i) {
1282                 std::string group_name = i->first;
1283
1284                 UNORDERED_MAP<std::string, GroupItems>::iterator
1285                         j = m_group_to_items.find(group_name);
1286                 if (j == m_group_to_items.end()) {
1287                         m_group_to_items[group_name].push_back(
1288                                 std::make_pair(id, i->second));
1289                 } else {
1290                         GroupItems &items = j->second;
1291                         items.push_back(std::make_pair(id, i->second));
1292                 }
1293         }
1294         return id;
1295 }
1296
1297
1298 content_t CNodeDefManager::allocateDummy(const std::string &name)
1299 {
1300         assert(name != "");     // Pre-condition
1301         ContentFeatures f;
1302         f.name = name;
1303         return set(name, f);
1304 }
1305
1306
1307 void CNodeDefManager::removeNode(const std::string &name)
1308 {
1309         // Pre-condition
1310         assert(name != "");
1311
1312         // Erase name from name ID mapping
1313         content_t id = CONTENT_IGNORE;
1314         if (m_name_id_mapping.getId(name, id)) {
1315                 m_name_id_mapping.eraseName(name);
1316                 m_name_id_mapping_with_aliases.erase(name);
1317         }
1318
1319         // Erase node content from all groups it belongs to
1320         for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
1321                         m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1322                 GroupItems &items = iter_groups->second;
1323                 for (GroupItems::iterator iter_groupitems = items.begin();
1324                                 iter_groupitems != items.end();) {
1325                         if (iter_groupitems->first == id)
1326                                 items.erase(iter_groupitems++);
1327                         else
1328                                 ++iter_groupitems;
1329                 }
1330
1331                 // Check if group is empty
1332                 if (items.size() == 0)
1333                         m_group_to_items.erase(iter_groups++);
1334                 else
1335                         ++iter_groups;
1336         }
1337 }
1338
1339
1340 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1341 {
1342         std::set<std::string> all;
1343         idef->getAll(all);
1344         m_name_id_mapping_with_aliases.clear();
1345         for (std::set<std::string>::const_iterator
1346                         i = all.begin(); i != all.end(); ++i) {
1347                 const std::string &name = *i;
1348                 const std::string &convert_to = idef->getAlias(name);
1349                 content_t id;
1350                 if (m_name_id_mapping.getId(convert_to, id)) {
1351                         m_name_id_mapping_with_aliases.insert(
1352                                 std::make_pair(name, id));
1353                 }
1354         }
1355 }
1356
1357 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1358 {
1359         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1360                 "overrides to textures from " << override_filepath << std::endl;
1361
1362         std::ifstream infile(override_filepath.c_str());
1363         std::string line;
1364         int line_c = 0;
1365         while (std::getline(infile, line)) {
1366                 line_c++;
1367                 if (trim(line) == "")
1368                         continue;
1369                 std::vector<std::string> splitted = str_split(line, ' ');
1370                 if (splitted.size() != 3) {
1371                         errorstream << override_filepath
1372                                 << ":" << line_c << " Could not apply texture override \""
1373                                 << line << "\": Syntax error" << std::endl;
1374                         continue;
1375                 }
1376
1377                 content_t id;
1378                 if (!getId(splitted[0], id))
1379                         continue; // Ignore unknown node
1380
1381                 ContentFeatures &nodedef = m_content_features[id];
1382
1383                 if (splitted[1] == "top")
1384                         nodedef.tiledef[0].name = splitted[2];
1385                 else if (splitted[1] == "bottom")
1386                         nodedef.tiledef[1].name = splitted[2];
1387                 else if (splitted[1] == "right")
1388                         nodedef.tiledef[2].name = splitted[2];
1389                 else if (splitted[1] == "left")
1390                         nodedef.tiledef[3].name = splitted[2];
1391                 else if (splitted[1] == "back")
1392                         nodedef.tiledef[4].name = splitted[2];
1393                 else if (splitted[1] == "front")
1394                         nodedef.tiledef[5].name = splitted[2];
1395                 else if (splitted[1] == "all" || splitted[1] == "*")
1396                         for (int i = 0; i < 6; i++)
1397                                 nodedef.tiledef[i].name = splitted[2];
1398                 else if (splitted[1] == "sides")
1399                         for (int i = 2; i < 6; i++)
1400                                 nodedef.tiledef[i].name = splitted[2];
1401                 else {
1402                         errorstream << override_filepath
1403                                 << ":" << line_c << " Could not apply texture override \""
1404                                 << line << "\": Unknown node side \""
1405                                 << splitted[1] << "\"" << std::endl;
1406                         continue;
1407                 }
1408         }
1409 }
1410
1411 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1412         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1413         void *progress_callback_args)
1414 {
1415 #ifndef SERVER
1416         infostream << "CNodeDefManager::updateTextures(): Updating "
1417                 "textures in node definitions" << std::endl;
1418
1419         Client *client = (Client *)gamedef;
1420         ITextureSource *tsrc = client->tsrc();
1421         IShaderSource *shdsrc = client->getShaderSource();
1422         scene::ISceneManager* smgr = client->getSceneManager();
1423         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1424         TextureSettings tsettings;
1425         tsettings.readSettings();
1426
1427         u32 size = m_content_features.size();
1428
1429         for (u32 i = 0; i < size; i++) {
1430                 ContentFeatures *f = &(m_content_features[i]);
1431                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1432                 progress_callback(progress_callback_args, i, size);
1433         }
1434 #endif
1435 }
1436
1437 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1438 {
1439         writeU8(os, 1); // version
1440         u16 count = 0;
1441         std::ostringstream os2(std::ios::binary);
1442         for (u32 i = 0; i < m_content_features.size(); i++) {
1443                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1444                                 || i == CONTENT_UNKNOWN)
1445                         continue;
1446                 const ContentFeatures *f = &m_content_features[i];
1447                 if (f->name == "")
1448                         continue;
1449                 writeU16(os2, i);
1450                 // Wrap it in a string to allow different lengths without
1451                 // strict version incompatibilities
1452                 std::ostringstream wrapper_os(std::ios::binary);
1453                 f->serialize(wrapper_os, protocol_version);
1454                 os2<<serializeString(wrapper_os.str());
1455
1456                 // must not overflow
1457                 u16 next = count + 1;
1458                 FATAL_ERROR_IF(next < count, "Overflow");
1459                 count++;
1460         }
1461         writeU16(os, count);
1462         os << serializeLongString(os2.str());
1463 }
1464
1465
1466 void CNodeDefManager::deSerialize(std::istream &is)
1467 {
1468         clear();
1469         int version = readU8(is);
1470         if (version != 1)
1471                 throw SerializationError("unsupported NodeDefinitionManager version");
1472         u16 count = readU16(is);
1473         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1474         ContentFeatures f;
1475         for (u16 n = 0; n < count; n++) {
1476                 u16 i = readU16(is2);
1477
1478                 // Read it from the string wrapper
1479                 std::string wrapper = deSerializeString(is2);
1480                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1481                 f.deSerialize(wrapper_is);
1482
1483                 // Check error conditions
1484                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1485                         warningstream << "NodeDefManager::deSerialize(): "
1486                                 "not changing builtin node " << i << std::endl;
1487                         continue;
1488                 }
1489                 if (f.name == "") {
1490                         warningstream << "NodeDefManager::deSerialize(): "
1491                                 "received empty name" << std::endl;
1492                         continue;
1493                 }
1494
1495                 // Ignore aliases
1496                 u16 existing_id;
1497                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1498                         warningstream << "NodeDefManager::deSerialize(): "
1499                                 "already defined with different ID: " << f.name << std::endl;
1500                         continue;
1501                 }
1502
1503                 // All is ok, add node definition with the requested ID
1504                 if (i >= m_content_features.size())
1505                         m_content_features.resize((u32)(i) + 1);
1506                 m_content_features[i] = f;
1507                 addNameIdMapping(i, f.name);
1508                 verbosestream << "deserialized " << f.name << std::endl;
1509
1510                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1511                 fixSelectionBoxIntUnion();
1512         }
1513 }
1514
1515
1516 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1517 {
1518         m_name_id_mapping.set(i, name);
1519         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1520 }
1521
1522
1523 IWritableNodeDefManager *createNodeDefManager()
1524 {
1525         return new CNodeDefManager();
1526 }
1527
1528
1529 //// Serialization of old ContentFeatures formats
1530 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1531 {
1532         u8 compatible_param_type_2 = param_type_2;
1533         if ((protocol_version < 28)
1534                         && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1535                 compatible_param_type_2 = CPT2_NONE;
1536         else if (protocol_version < 30) {
1537                 if (compatible_param_type_2 == CPT2_COLOR)
1538                         compatible_param_type_2 = CPT2_NONE;
1539                 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1540                         compatible_param_type_2 = CPT2_FACEDIR;
1541                 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1542                         compatible_param_type_2 = CPT2_WALLMOUNTED;
1543         }
1544
1545         float compatible_visual_scale = visual_scale;
1546         if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1547                 compatible_visual_scale = sqrt(visual_scale);
1548
1549         TileDef compatible_tiles[6];
1550         for (u8 i = 0; i < 6; i++) {
1551                 compatible_tiles[i] = tiledef[i];
1552                 if (tiledef_overlay[i].name != "") {
1553                         std::stringstream s;
1554                         s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
1555                                 << ")";
1556                         compatible_tiles[i].name = s.str();
1557                 }
1558         }
1559
1560         // Protocol >= 24
1561         if (protocol_version < 31) {
1562                 writeU8(os, protocol_version < 27 ? 7 : 8);
1563
1564                 os << serializeString(name);
1565                 writeU16(os, groups.size());
1566                 for (ItemGroupList::const_iterator i = groups.begin();
1567                                 i != groups.end(); ++i) {
1568                         os << serializeString(i->first);
1569                         writeS16(os, i->second);
1570                 }
1571                 writeU8(os, drawtype);
1572                 writeF1000(os, compatible_visual_scale);
1573                 writeU8(os, 6);
1574                 for (u32 i = 0; i < 6; i++)
1575                         compatible_tiles[i].serialize(os, protocol_version);
1576                 writeU8(os, CF_SPECIAL_COUNT);
1577                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1578                         tiledef_special[i].serialize(os, protocol_version);
1579                 writeU8(os, alpha);
1580                 writeU8(os, post_effect_color.getAlpha());
1581                 writeU8(os, post_effect_color.getRed());
1582                 writeU8(os, post_effect_color.getGreen());
1583                 writeU8(os, post_effect_color.getBlue());
1584                 writeU8(os, param_type);
1585                 writeU8(os, compatible_param_type_2);
1586                 writeU8(os, is_ground_content);
1587                 writeU8(os, light_propagates);
1588                 writeU8(os, sunlight_propagates);
1589                 writeU8(os, walkable);
1590                 writeU8(os, pointable);
1591                 writeU8(os, diggable);
1592                 writeU8(os, climbable);
1593                 writeU8(os, buildable_to);
1594                 os << serializeString(""); // legacy: used to be metadata_name
1595                 writeU8(os, liquid_type);
1596                 os << serializeString(liquid_alternative_flowing);
1597                 os << serializeString(liquid_alternative_source);
1598                 writeU8(os, liquid_viscosity);
1599                 writeU8(os, liquid_renewable);
1600                 writeU8(os, light_source);
1601                 writeU32(os, damage_per_second);
1602                 node_box.serialize(os, protocol_version);
1603                 selection_box.serialize(os, protocol_version);
1604                 writeU8(os, legacy_facedir_simple);
1605                 writeU8(os, legacy_wallmounted);
1606                 serializeSimpleSoundSpec(sound_footstep, os);
1607                 serializeSimpleSoundSpec(sound_dig, os);
1608                 serializeSimpleSoundSpec(sound_dug, os);
1609                 writeU8(os, rightclickable);
1610                 writeU8(os, drowning);
1611                 writeU8(os, leveled);
1612                 writeU8(os, liquid_range);
1613                 writeU8(os, waving);
1614                 os << serializeString(mesh);
1615                 collision_box.serialize(os, protocol_version);
1616                 writeU8(os, floodable);
1617                 writeU16(os, connects_to_ids.size());
1618                 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1619                                 i != connects_to_ids.end(); ++i)
1620                         writeU16(os, *i);
1621                 writeU8(os, connect_sides);
1622         } else {
1623                 throw SerializationError("ContentFeatures::serialize(): "
1624                         "Unsupported version requested");
1625         }
1626 }
1627
1628 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1629 {
1630         if (version == 5) // In PROTOCOL_VERSION 13
1631         {
1632                 name = deSerializeString(is);
1633                 groups.clear();
1634                 u32 groups_size = readU16(is);
1635                 for(u32 i=0; i<groups_size; i++){
1636                         std::string name = deSerializeString(is);
1637                         int value = readS16(is);
1638                         groups[name] = value;
1639                 }
1640                 drawtype = (enum NodeDrawType)readU8(is);
1641
1642                 visual_scale = readF1000(is);
1643                 if (readU8(is) != 6)
1644                         throw SerializationError("unsupported tile count");
1645                 for (u32 i = 0; i < 6; i++)
1646                         tiledef[i].deSerialize(is, version, drawtype);
1647                 if (readU8(is) != CF_SPECIAL_COUNT)
1648                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1649                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1650                         tiledef_special[i].deSerialize(is, version, drawtype);
1651                 alpha = readU8(is);
1652                 post_effect_color.setAlpha(readU8(is));
1653                 post_effect_color.setRed(readU8(is));
1654                 post_effect_color.setGreen(readU8(is));
1655                 post_effect_color.setBlue(readU8(is));
1656                 param_type = (enum ContentParamType)readU8(is);
1657                 param_type_2 = (enum ContentParamType2)readU8(is);
1658                 is_ground_content = readU8(is);
1659                 light_propagates = readU8(is);
1660                 sunlight_propagates = readU8(is);
1661                 walkable = readU8(is);
1662                 pointable = readU8(is);
1663                 diggable = readU8(is);
1664                 climbable = readU8(is);
1665                 buildable_to = readU8(is);
1666                 deSerializeString(is); // legacy: used to be metadata_name
1667                 liquid_type = (enum LiquidType)readU8(is);
1668                 liquid_alternative_flowing = deSerializeString(is);
1669                 liquid_alternative_source = deSerializeString(is);
1670                 liquid_viscosity = readU8(is);
1671                 light_source = readU8(is);
1672                 light_source = MYMIN(light_source, LIGHT_MAX);
1673                 damage_per_second = readU32(is);
1674                 node_box.deSerialize(is);
1675                 selection_box.deSerialize(is);
1676                 legacy_facedir_simple = readU8(is);
1677                 legacy_wallmounted = readU8(is);
1678                 deSerializeSimpleSoundSpec(sound_footstep, is);
1679                 deSerializeSimpleSoundSpec(sound_dig, is);
1680                 deSerializeSimpleSoundSpec(sound_dug, is);
1681         } else if (version == 6) {
1682                 name = deSerializeString(is);
1683                 groups.clear();
1684                 u32 groups_size = readU16(is);
1685                 for (u32 i = 0; i < groups_size; i++) {
1686                         std::string name = deSerializeString(is);
1687                         int     value = readS16(is);
1688                         groups[name] = value;
1689                 }
1690                 drawtype = (enum NodeDrawType)readU8(is);
1691                 visual_scale = readF1000(is);
1692                 if (readU8(is) != 6)
1693                         throw SerializationError("unsupported tile count");
1694                 for (u32 i = 0; i < 6; i++)
1695                         tiledef[i].deSerialize(is, version, drawtype);
1696                 // CF_SPECIAL_COUNT in version 6 = 2
1697                 if (readU8(is) != 2)
1698                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1699                 for (u32 i = 0; i < 2; i++)
1700                         tiledef_special[i].deSerialize(is, version, drawtype);
1701                 alpha = readU8(is);
1702                 post_effect_color.setAlpha(readU8(is));
1703                 post_effect_color.setRed(readU8(is));
1704                 post_effect_color.setGreen(readU8(is));
1705                 post_effect_color.setBlue(readU8(is));
1706                 param_type = (enum ContentParamType)readU8(is);
1707                 param_type_2 = (enum ContentParamType2)readU8(is);
1708                 is_ground_content = readU8(is);
1709                 light_propagates = readU8(is);
1710                 sunlight_propagates = readU8(is);
1711                 walkable = readU8(is);
1712                 pointable = readU8(is);
1713                 diggable = readU8(is);
1714                 climbable = readU8(is);
1715                 buildable_to = readU8(is);
1716                 deSerializeString(is); // legacy: used to be metadata_name
1717                 liquid_type = (enum LiquidType)readU8(is);
1718                 liquid_alternative_flowing = deSerializeString(is);
1719                 liquid_alternative_source = deSerializeString(is);
1720                 liquid_viscosity = readU8(is);
1721                 liquid_renewable = readU8(is);
1722                 light_source = readU8(is);
1723                 damage_per_second = readU32(is);
1724                 node_box.deSerialize(is);
1725                 selection_box.deSerialize(is);
1726                 legacy_facedir_simple = readU8(is);
1727                 legacy_wallmounted = readU8(is);
1728                 deSerializeSimpleSoundSpec(sound_footstep, is);
1729                 deSerializeSimpleSoundSpec(sound_dig, is);
1730                 deSerializeSimpleSoundSpec(sound_dug, is);
1731                 rightclickable = readU8(is);
1732                 drowning = readU8(is);
1733                 leveled = readU8(is);
1734                 liquid_range = readU8(is);
1735         } else if (version == 7 || version == 8){
1736                 name = deSerializeString(is);
1737                 groups.clear();
1738                 u32 groups_size = readU16(is);
1739                 for (u32 i = 0; i < groups_size; i++) {
1740                         std::string name = deSerializeString(is);
1741                         int value = readS16(is);
1742                         groups[name] = value;
1743                 }
1744                 drawtype = (enum NodeDrawType) readU8(is);
1745
1746                 visual_scale = readF1000(is);
1747                 if (readU8(is) != 6)
1748                         throw SerializationError("unsupported tile count");
1749                 for (u32 i = 0; i < 6; i++)
1750                         tiledef[i].deSerialize(is, version, drawtype);
1751                 if (readU8(is) != CF_SPECIAL_COUNT)
1752                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1753                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1754                         tiledef_special[i].deSerialize(is, version, drawtype);
1755                 alpha = readU8(is);
1756                 post_effect_color.setAlpha(readU8(is));
1757                 post_effect_color.setRed(readU8(is));
1758                 post_effect_color.setGreen(readU8(is));
1759                 post_effect_color.setBlue(readU8(is));
1760                 param_type = (enum ContentParamType) readU8(is);
1761                 param_type_2 = (enum ContentParamType2) readU8(is);
1762                 is_ground_content = readU8(is);
1763                 light_propagates = readU8(is);
1764                 sunlight_propagates = readU8(is);
1765                 walkable = readU8(is);
1766                 pointable = readU8(is);
1767                 diggable = readU8(is);
1768                 climbable = readU8(is);
1769                 buildable_to = readU8(is);
1770                 deSerializeString(is); // legacy: used to be metadata_name
1771                 liquid_type = (enum LiquidType) readU8(is);
1772                 liquid_alternative_flowing = deSerializeString(is);
1773                 liquid_alternative_source = deSerializeString(is);
1774                 liquid_viscosity = readU8(is);
1775                 liquid_renewable = readU8(is);
1776                 light_source = readU8(is);
1777                 light_source = MYMIN(light_source, LIGHT_MAX);
1778                 damage_per_second = readU32(is);
1779                 node_box.deSerialize(is);
1780                 selection_box.deSerialize(is);
1781                 legacy_facedir_simple = readU8(is);
1782                 legacy_wallmounted = readU8(is);
1783                 deSerializeSimpleSoundSpec(sound_footstep, is);
1784                 deSerializeSimpleSoundSpec(sound_dig, is);
1785                 deSerializeSimpleSoundSpec(sound_dug, is);
1786                 rightclickable = readU8(is);
1787                 drowning = readU8(is);
1788                 leveled = readU8(is);
1789                 liquid_range = readU8(is);
1790                 waving = readU8(is);
1791                 try {
1792                         mesh = deSerializeString(is);
1793                         collision_box.deSerialize(is);
1794                         floodable = readU8(is);
1795                         u16 connects_to_size = readU16(is);
1796                         connects_to_ids.clear();
1797                         for (u16 i = 0; i < connects_to_size; i++)
1798                                 connects_to_ids.insert(readU16(is));
1799                         connect_sides = readU8(is);
1800                 } catch (SerializationError &e) {};
1801         }else{
1802                 throw SerializationError("unsupported ContentFeatures version");
1803         }
1804 }
1805
1806
1807 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1808 {
1809         return m_node_registration_complete;
1810 }
1811
1812
1813 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1814 {
1815         m_node_registration_complete = completed;
1816 }
1817
1818
1819 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1820 {
1821         nr->m_ndef = this;
1822         if (m_node_registration_complete)
1823                 nr->nodeResolveInternal();
1824         else
1825                 m_pending_resolve_callbacks.push_back(nr);
1826 }
1827
1828
1829 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1830 {
1831         size_t len = m_pending_resolve_callbacks.size();
1832         for (size_t i = 0; i != len; i++) {
1833                 if (nr != m_pending_resolve_callbacks[i])
1834                         continue;
1835
1836                 len--;
1837                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1838                 m_pending_resolve_callbacks.resize(len);
1839                 return true;
1840         }
1841
1842         return false;
1843 }
1844
1845
1846 void CNodeDefManager::runNodeResolveCallbacks()
1847 {
1848         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1849                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1850                 nr->nodeResolveInternal();
1851         }
1852
1853         m_pending_resolve_callbacks.clear();
1854 }
1855
1856
1857 void CNodeDefManager::resetNodeResolveState()
1858 {
1859         m_node_registration_complete = false;
1860         m_pending_resolve_callbacks.clear();
1861 }
1862
1863 void CNodeDefManager::mapNodeboxConnections()
1864 {
1865         for (u32 i = 0; i < m_content_features.size(); i++) {
1866                 ContentFeatures *f = &m_content_features[i];
1867                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1868                         continue;
1869                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1870                                 it != f->connects_to.end(); ++it) {
1871                         getIds(*it, f->connects_to_ids);
1872                 }
1873         }
1874 }
1875
1876 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1877 {
1878         const ContentFeatures &f1 = get(from);
1879
1880         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1881                 return false;
1882
1883         // lookup target in connected set
1884         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1885                 return false;
1886
1887         const ContentFeatures &f2 = get(to);
1888
1889         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1890                 // ignores actually looking if back connection exists
1891                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1892
1893         // does to node declare usable faces?
1894         if (f2.connect_sides > 0) {
1895                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1896                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1897                                 && (connect_face >= 4)) {
1898                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1899                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1900                                 0, // 4 - back
1901                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1902                                 0, // 8 - right
1903                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1904                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1905                                 0, // 16 - front
1906                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1907                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1908                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1909                                 };
1910                         return (f2.connect_sides
1911                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1912                 }
1913                 return (f2.connect_sides & connect_face);
1914         }
1915         // the target is just a regular node, so connect no matter back connection
1916         return true;
1917 }
1918
1919 ////
1920 //// NodeResolver
1921 ////
1922
1923 NodeResolver::NodeResolver()
1924 {
1925         m_ndef            = NULL;
1926         m_nodenames_idx   = 0;
1927         m_nnlistsizes_idx = 0;
1928         m_resolve_done    = false;
1929
1930         m_nodenames.reserve(16);
1931         m_nnlistsizes.reserve(4);
1932 }
1933
1934
1935 NodeResolver::~NodeResolver()
1936 {
1937         if (!m_resolve_done && m_ndef)
1938                 m_ndef->cancelNodeResolveCallback(this);
1939 }
1940
1941
1942 void NodeResolver::nodeResolveInternal()
1943 {
1944         m_nodenames_idx   = 0;
1945         m_nnlistsizes_idx = 0;
1946
1947         resolveNodeNames();
1948         m_resolve_done = true;
1949
1950         m_nodenames.clear();
1951         m_nnlistsizes.clear();
1952 }
1953
1954
1955 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1956         const std::string &node_alt, content_t c_fallback)
1957 {
1958         if (m_nodenames_idx == m_nodenames.size()) {
1959                 *result_out = c_fallback;
1960                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1961                 return false;
1962         }
1963
1964         content_t c;
1965         std::string name = m_nodenames[m_nodenames_idx++];
1966
1967         bool success = m_ndef->getId(name, c);
1968         if (!success && node_alt != "") {
1969                 name = node_alt;
1970                 success = m_ndef->getId(name, c);
1971         }
1972
1973         if (!success) {
1974                 errorstream << "NodeResolver: failed to resolve node name '" << name
1975                         << "'." << std::endl;
1976                 c = c_fallback;
1977         }
1978
1979         *result_out = c;
1980         return success;
1981 }
1982
1983
1984 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1985         bool all_required, content_t c_fallback)
1986 {
1987         bool success = true;
1988
1989         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1990                 errorstream << "NodeResolver: no more node lists" << std::endl;
1991                 return false;
1992         }
1993
1994         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1995
1996         while (length--) {
1997                 if (m_nodenames_idx == m_nodenames.size()) {
1998                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1999                         return false;
2000                 }
2001
2002                 content_t c;
2003                 std::string &name = m_nodenames[m_nodenames_idx++];
2004
2005                 if (name.substr(0,6) != "group:") {
2006                         if (m_ndef->getId(name, c)) {
2007                                 result_out->push_back(c);
2008                         } else if (all_required) {
2009                                 errorstream << "NodeResolver: failed to resolve node name '"
2010                                         << name << "'." << std::endl;
2011                                 result_out->push_back(c_fallback);
2012                                 success = false;
2013                         }
2014                 } else {
2015                         std::set<content_t> cids;
2016                         std::set<content_t>::iterator it;
2017                         m_ndef->getIds(name, cids);
2018                         for (it = cids.begin(); it != cids.end(); ++it)
2019                                 result_out->push_back(*it);
2020                 }
2021         }
2022
2023         return success;
2024 }