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