2ac59f8aef798297bfd4ac392174f8486a437aed
[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 bool getNodeRegistrationStatus() const;
885         inline virtual void setNodeRegistrationStatus(bool completed);
886
887         virtual void pendNodeResolve(NodeResolver *nr);
888         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
889         virtual void runNodeResolveCallbacks();
890         virtual void resetNodeResolveState();
891         virtual void mapNodeboxConnections();
892         virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
893         virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
894         {
895                 return m_selection_box_int_union;
896         }
897
898 private:
899         void addNameIdMapping(content_t i, std::string name);
900         /*!
901          * Recalculates m_selection_box_int_union based on
902          * m_selection_box_union.
903          */
904         void fixSelectionBoxIntUnion();
905
906         // Features indexed by id
907         std::vector<ContentFeatures> m_content_features;
908
909         // A mapping for fast converting back and forth between names and ids
910         NameIdMapping m_name_id_mapping;
911
912         // Like m_name_id_mapping, but only from names to ids, and includes
913         // item aliases too. Updated by updateAliases()
914         // Note: Not serialized.
915
916         UNORDERED_MAP<std::string, content_t> m_name_id_mapping_with_aliases;
917
918         // A mapping from groups to a list of content_ts (and their levels)
919         // that belong to it.  Necessary for a direct lookup in getIds().
920         // Note: Not serialized.
921         UNORDERED_MAP<std::string, GroupItems> m_group_to_items;
922
923         // Next possibly free id
924         content_t m_next_id;
925
926         // NodeResolvers to callback once node registration has ended
927         std::vector<NodeResolver *> m_pending_resolve_callbacks;
928
929         // True when all nodes have been registered
930         bool m_node_registration_complete;
931
932         //! The union of all nodes' selection boxes.
933         aabb3f m_selection_box_union;
934         /*!
935          * The smallest box in node coordinates that
936          * contains all nodes' selection boxes.
937          */
938         core::aabbox3d<s16> m_selection_box_int_union;
939 };
940
941
942 CNodeDefManager::CNodeDefManager()
943 {
944         clear();
945 }
946
947
948 CNodeDefManager::~CNodeDefManager()
949 {
950 #ifndef SERVER
951         for (u32 i = 0; i < m_content_features.size(); i++) {
952                 ContentFeatures *f = &m_content_features[i];
953                 for (u32 j = 0; j < 24; j++) {
954                         if (f->mesh_ptr[j])
955                                 f->mesh_ptr[j]->drop();
956                 }
957         }
958 #endif
959 }
960
961
962 void CNodeDefManager::clear()
963 {
964         m_content_features.clear();
965         m_name_id_mapping.clear();
966         m_name_id_mapping_with_aliases.clear();
967         m_group_to_items.clear();
968         m_next_id = 0;
969         m_selection_box_union.reset(0,0,0);
970         m_selection_box_int_union.reset(0,0,0);
971
972         resetNodeResolveState();
973
974         u32 initial_length = 0;
975         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
976         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
977         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
978         m_content_features.resize(initial_length);
979
980         // Set CONTENT_UNKNOWN
981         {
982                 ContentFeatures f;
983                 f.name = "unknown";
984                 // Insert directly into containers
985                 content_t c = CONTENT_UNKNOWN;
986                 m_content_features[c] = f;
987                 addNameIdMapping(c, f.name);
988         }
989
990         // Set CONTENT_AIR
991         {
992                 ContentFeatures f;
993                 f.name                = "air";
994                 f.drawtype            = NDT_AIRLIKE;
995                 f.param_type          = CPT_LIGHT;
996                 f.light_propagates    = true;
997                 f.sunlight_propagates = true;
998                 f.walkable            = false;
999                 f.pointable           = false;
1000                 f.diggable            = false;
1001                 f.buildable_to        = true;
1002                 f.floodable           = true;
1003                 f.is_ground_content   = true;
1004                 // Insert directly into containers
1005                 content_t c = CONTENT_AIR;
1006                 m_content_features[c] = f;
1007                 addNameIdMapping(c, f.name);
1008         }
1009
1010         // Set CONTENT_IGNORE
1011         {
1012                 ContentFeatures f;
1013                 f.name                = "ignore";
1014                 f.drawtype            = NDT_AIRLIKE;
1015                 f.param_type          = CPT_NONE;
1016                 f.light_propagates    = false;
1017                 f.sunlight_propagates = false;
1018                 f.walkable            = false;
1019                 f.pointable           = false;
1020                 f.diggable            = false;
1021                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
1022                 f.is_ground_content   = true;
1023                 // Insert directly into containers
1024                 content_t c = CONTENT_IGNORE;
1025                 m_content_features[c] = f;
1026                 addNameIdMapping(c, f.name);
1027         }
1028 }
1029
1030
1031 IWritableNodeDefManager *CNodeDefManager::clone()
1032 {
1033         CNodeDefManager *mgr = new CNodeDefManager();
1034         *mgr = *this;
1035         return mgr;
1036 }
1037
1038
1039 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1040 {
1041         return c < m_content_features.size()
1042                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1043 }
1044
1045
1046 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1047 {
1048         return get(n.getContent());
1049 }
1050
1051
1052 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1053 {
1054         UNORDERED_MAP<std::string, content_t>::const_iterator
1055                 i = m_name_id_mapping_with_aliases.find(name);
1056         if(i == m_name_id_mapping_with_aliases.end())
1057                 return false;
1058         result = i->second;
1059         return true;
1060 }
1061
1062
1063 content_t CNodeDefManager::getId(const std::string &name) const
1064 {
1065         content_t id = CONTENT_IGNORE;
1066         getId(name, id);
1067         return id;
1068 }
1069
1070
1071 bool CNodeDefManager::getIds(const std::string &name,
1072                 std::set<content_t> &result) const
1073 {
1074         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1075         if (name.substr(0,6) != "group:") {
1076                 content_t id = CONTENT_IGNORE;
1077                 bool exists = getId(name, id);
1078                 if (exists)
1079                         result.insert(id);
1080                 return exists;
1081         }
1082         std::string group = name.substr(6);
1083
1084         UNORDERED_MAP<std::string, GroupItems>::const_iterator
1085                 i = m_group_to_items.find(group);
1086         if (i == m_group_to_items.end())
1087                 return true;
1088
1089         const GroupItems &items = i->second;
1090         for (GroupItems::const_iterator j = items.begin();
1091                 j != items.end(); ++j) {
1092                 if ((*j).second != 0)
1093                         result.insert((*j).first);
1094         }
1095         //printf("getIds: %dus\n", t.stop());
1096         return true;
1097 }
1098
1099
1100 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1101 {
1102         content_t id = CONTENT_UNKNOWN;
1103         getId(name, id);
1104         return get(id);
1105 }
1106
1107
1108 // returns CONTENT_IGNORE if no free ID found
1109 content_t CNodeDefManager::allocateId()
1110 {
1111         for (content_t id = m_next_id;
1112                         id >= m_next_id; // overflow?
1113                         ++id) {
1114                 while (id >= m_content_features.size()) {
1115                         m_content_features.push_back(ContentFeatures());
1116                 }
1117                 const ContentFeatures &f = m_content_features[id];
1118                 if (f.name == "") {
1119                         m_next_id = id + 1;
1120                         return id;
1121                 }
1122         }
1123         // If we arrive here, an overflow occurred in id.
1124         // That means no ID was found
1125         return CONTENT_IGNORE;
1126 }
1127
1128
1129 /*!
1130  * Returns the smallest box that contains all boxes
1131  * in the vector. Box_union is expanded.
1132  * @param[in]      boxes     the vector containing the boxes
1133  * @param[in, out] box_union the union of the arguments
1134  */
1135 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1136 {
1137         for (std::vector<aabb3f>::const_iterator it = boxes.begin();
1138                         it != boxes.end(); ++it) {
1139                 box_union->addInternalBox(*it);
1140         }
1141 }
1142
1143
1144 /*!
1145  * Returns a box that contains the nodebox in every case.
1146  * The argument node_union is expanded.
1147  * @param[in]      nodebox  the nodebox to be measured
1148  * @param[in]      features  used to decide whether the nodebox
1149  * can be rotated
1150  * @param[in, out] box_union the union of the arguments
1151  */
1152 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1153         aabb3f *box_union)
1154 {
1155         switch(nodebox.type) {
1156                 case NODEBOX_FIXED:
1157                 case NODEBOX_LEVELED: {
1158                         // Raw union
1159                         aabb3f half_processed(0, 0, 0, 0, 0, 0);
1160                         boxVectorUnion(nodebox.fixed, &half_processed);
1161                         // Set leveled boxes to maximal
1162                         if (nodebox.type == NODEBOX_LEVELED) {
1163                                 half_processed.MaxEdge.Y = +BS / 2;
1164                         }
1165                         if (features.param_type_2 == CPT2_FACEDIR ||
1166                                         features.param_type_2 == CPT2_COLORED_FACEDIR) {
1167                                 // Get maximal coordinate
1168                                 f32 coords[] = {
1169                                         fabsf(half_processed.MinEdge.X),
1170                                         fabsf(half_processed.MinEdge.Y),
1171                                         fabsf(half_processed.MinEdge.Z),
1172                                         fabsf(half_processed.MaxEdge.X),
1173                                         fabsf(half_processed.MaxEdge.Y),
1174                                         fabsf(half_processed.MaxEdge.Z) };
1175                                 f32 max = 0;
1176                                 for (int i = 0; i < 6; i++) {
1177                                         if (max < coords[i]) {
1178                                                 max = coords[i];
1179                                         }
1180                                 }
1181                                 // Add the union of all possible rotated boxes
1182                                 box_union->addInternalPoint(-max, -max, -max);
1183                                 box_union->addInternalPoint(+max, +max, +max);
1184                         } else {
1185                                 box_union->addInternalBox(half_processed);
1186                         }
1187                         break;
1188                 }
1189                 case NODEBOX_WALLMOUNTED: {
1190                         // Add fix boxes
1191                         box_union->addInternalBox(nodebox.wall_top);
1192                         box_union->addInternalBox(nodebox.wall_bottom);
1193                         // Find maximal coordinate in the X-Z plane
1194                         f32 coords[] = {
1195                                 fabsf(nodebox.wall_side.MinEdge.X),
1196                                 fabsf(nodebox.wall_side.MinEdge.Z),
1197                                 fabsf(nodebox.wall_side.MaxEdge.X),
1198                                 fabsf(nodebox.wall_side.MaxEdge.Z) };
1199                         f32 max = 0;
1200                         for (int i = 0; i < 4; i++) {
1201                                 if (max < coords[i]) {
1202                                         max = coords[i];
1203                                 }
1204                         }
1205                         // Add the union of all possible rotated boxes
1206                         box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1207                         box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1208                         break;
1209                 }
1210                 case NODEBOX_CONNECTED: {
1211                         // Add all possible connected boxes
1212                         boxVectorUnion(nodebox.fixed,          box_union);
1213                         boxVectorUnion(nodebox.connect_top,    box_union);
1214                         boxVectorUnion(nodebox.connect_bottom, box_union);
1215                         boxVectorUnion(nodebox.connect_front,  box_union);
1216                         boxVectorUnion(nodebox.connect_left,   box_union);
1217                         boxVectorUnion(nodebox.connect_back,   box_union);
1218                         boxVectorUnion(nodebox.connect_right,  box_union);
1219                         break;
1220                 }
1221                 default: {
1222                         // NODEBOX_REGULAR
1223                         box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1224                         box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1225                 }
1226         }
1227 }
1228
1229
1230 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1231 {
1232         m_selection_box_int_union.MinEdge.X = floorf(
1233                 m_selection_box_union.MinEdge.X / BS + 0.5f);
1234         m_selection_box_int_union.MinEdge.Y = floorf(
1235                 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1236         m_selection_box_int_union.MinEdge.Z = floorf(
1237                 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1238         m_selection_box_int_union.MaxEdge.X = ceilf(
1239                 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1240         m_selection_box_int_union.MaxEdge.Y = ceilf(
1241                 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1242         m_selection_box_int_union.MaxEdge.Z = ceilf(
1243                 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1244 }
1245
1246
1247 // IWritableNodeDefManager
1248 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1249 {
1250         // Pre-conditions
1251         assert(name != "");
1252         assert(name == def.name);
1253
1254         // Don't allow redefining ignore (but allow air and unknown)
1255         if (name == "ignore") {
1256                 warningstream << "NodeDefManager: Ignoring "
1257                         "CONTENT_IGNORE redefinition"<<std::endl;
1258                 return CONTENT_IGNORE;
1259         }
1260
1261         content_t id = CONTENT_IGNORE;
1262         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1263                 // Get new id
1264                 id = allocateId();
1265                 if (id == CONTENT_IGNORE) {
1266                         warningstream << "NodeDefManager: Absolute "
1267                                 "limit reached" << std::endl;
1268                         return CONTENT_IGNORE;
1269                 }
1270                 assert(id != CONTENT_IGNORE);
1271                 addNameIdMapping(id, name);
1272         }
1273         m_content_features[id] = def;
1274         verbosestream << "NodeDefManager: registering content id \"" << id
1275                 << "\": name=\"" << def.name << "\""<<std::endl;
1276
1277         getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1278         fixSelectionBoxIntUnion();
1279         // Add this content to the list of all groups it belongs to
1280         // FIXME: This should remove a node from groups it no longer
1281         // belongs to when a node is re-registered
1282         for (ItemGroupList::const_iterator i = def.groups.begin();
1283                 i != def.groups.end(); ++i) {
1284                 std::string group_name = i->first;
1285
1286                 UNORDERED_MAP<std::string, GroupItems>::iterator
1287                         j = m_group_to_items.find(group_name);
1288                 if (j == m_group_to_items.end()) {
1289                         m_group_to_items[group_name].push_back(
1290                                 std::make_pair(id, i->second));
1291                 } else {
1292                         GroupItems &items = j->second;
1293                         items.push_back(std::make_pair(id, i->second));
1294                 }
1295         }
1296         return id;
1297 }
1298
1299
1300 content_t CNodeDefManager::allocateDummy(const std::string &name)
1301 {
1302         assert(name != "");     // Pre-condition
1303         ContentFeatures f;
1304         f.name = name;
1305         return set(name, f);
1306 }
1307
1308
1309 void CNodeDefManager::removeNode(const std::string &name)
1310 {
1311         // Pre-condition
1312         assert(name != "");
1313
1314         // Erase name from name ID mapping
1315         content_t id = CONTENT_IGNORE;
1316         if (m_name_id_mapping.getId(name, id)) {
1317                 m_name_id_mapping.eraseName(name);
1318                 m_name_id_mapping_with_aliases.erase(name);
1319         }
1320
1321         // Erase node content from all groups it belongs to
1322         for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
1323                         m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1324                 GroupItems &items = iter_groups->second;
1325                 for (GroupItems::iterator iter_groupitems = items.begin();
1326                                 iter_groupitems != items.end();) {
1327                         if (iter_groupitems->first == id)
1328                                 items.erase(iter_groupitems++);
1329                         else
1330                                 ++iter_groupitems;
1331                 }
1332
1333                 // Check if group is empty
1334                 if (items.size() == 0)
1335                         m_group_to_items.erase(iter_groups++);
1336                 else
1337                         ++iter_groups;
1338         }
1339 }
1340
1341
1342 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1343 {
1344         std::set<std::string> all;
1345         idef->getAll(all);
1346         m_name_id_mapping_with_aliases.clear();
1347         for (std::set<std::string>::const_iterator
1348                         i = all.begin(); i != all.end(); ++i) {
1349                 const std::string &name = *i;
1350                 const std::string &convert_to = idef->getAlias(name);
1351                 content_t id;
1352                 if (m_name_id_mapping.getId(convert_to, id)) {
1353                         m_name_id_mapping_with_aliases.insert(
1354                                 std::make_pair(name, id));
1355                 }
1356         }
1357 }
1358
1359 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1360 {
1361         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1362                 "overrides to textures from " << override_filepath << std::endl;
1363
1364         std::ifstream infile(override_filepath.c_str());
1365         std::string line;
1366         int line_c = 0;
1367         while (std::getline(infile, line)) {
1368                 line_c++;
1369                 if (trim(line) == "")
1370                         continue;
1371                 std::vector<std::string> splitted = str_split(line, ' ');
1372                 if (splitted.size() != 3) {
1373                         errorstream << override_filepath
1374                                 << ":" << line_c << " Could not apply texture override \""
1375                                 << line << "\": Syntax error" << std::endl;
1376                         continue;
1377                 }
1378
1379                 content_t id;
1380                 if (!getId(splitted[0], id))
1381                         continue; // Ignore unknown node
1382
1383                 ContentFeatures &nodedef = m_content_features[id];
1384
1385                 if (splitted[1] == "top")
1386                         nodedef.tiledef[0].name = splitted[2];
1387                 else if (splitted[1] == "bottom")
1388                         nodedef.tiledef[1].name = splitted[2];
1389                 else if (splitted[1] == "right")
1390                         nodedef.tiledef[2].name = splitted[2];
1391                 else if (splitted[1] == "left")
1392                         nodedef.tiledef[3].name = splitted[2];
1393                 else if (splitted[1] == "back")
1394                         nodedef.tiledef[4].name = splitted[2];
1395                 else if (splitted[1] == "front")
1396                         nodedef.tiledef[5].name = splitted[2];
1397                 else if (splitted[1] == "all" || splitted[1] == "*")
1398                         for (int i = 0; i < 6; i++)
1399                                 nodedef.tiledef[i].name = splitted[2];
1400                 else if (splitted[1] == "sides")
1401                         for (int i = 2; i < 6; i++)
1402                                 nodedef.tiledef[i].name = splitted[2];
1403                 else {
1404                         errorstream << override_filepath
1405                                 << ":" << line_c << " Could not apply texture override \""
1406                                 << line << "\": Unknown node side \""
1407                                 << splitted[1] << "\"" << std::endl;
1408                         continue;
1409                 }
1410         }
1411 }
1412
1413 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1414         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1415         void *progress_callback_args)
1416 {
1417 #ifndef SERVER
1418         infostream << "CNodeDefManager::updateTextures(): Updating "
1419                 "textures in node definitions" << std::endl;
1420
1421         Client *client = (Client *)gamedef;
1422         ITextureSource *tsrc = client->tsrc();
1423         IShaderSource *shdsrc = client->getShaderSource();
1424         scene::ISceneManager* smgr = client->getSceneManager();
1425         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1426         TextureSettings tsettings;
1427         tsettings.readSettings();
1428
1429         u32 size = m_content_features.size();
1430
1431         for (u32 i = 0; i < size; i++) {
1432                 ContentFeatures *f = &(m_content_features[i]);
1433                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1434                 progress_callback(progress_callback_args, i, size);
1435         }
1436 #endif
1437 }
1438
1439 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1440 {
1441         writeU8(os, 1); // version
1442         u16 count = 0;
1443         std::ostringstream os2(std::ios::binary);
1444         for (u32 i = 0; i < m_content_features.size(); i++) {
1445                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1446                                 || i == CONTENT_UNKNOWN)
1447                         continue;
1448                 const ContentFeatures *f = &m_content_features[i];
1449                 if (f->name == "")
1450                         continue;
1451                 writeU16(os2, i);
1452                 // Wrap it in a string to allow different lengths without
1453                 // strict version incompatibilities
1454                 std::ostringstream wrapper_os(std::ios::binary);
1455                 f->serialize(wrapper_os, protocol_version);
1456                 os2<<serializeString(wrapper_os.str());
1457
1458                 // must not overflow
1459                 u16 next = count + 1;
1460                 FATAL_ERROR_IF(next < count, "Overflow");
1461                 count++;
1462         }
1463         writeU16(os, count);
1464         os << serializeLongString(os2.str());
1465 }
1466
1467
1468 void CNodeDefManager::deSerialize(std::istream &is)
1469 {
1470         clear();
1471         int version = readU8(is);
1472         if (version != 1)
1473                 throw SerializationError("unsupported NodeDefinitionManager version");
1474         u16 count = readU16(is);
1475         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1476         ContentFeatures f;
1477         for (u16 n = 0; n < count; n++) {
1478                 u16 i = readU16(is2);
1479
1480                 // Read it from the string wrapper
1481                 std::string wrapper = deSerializeString(is2);
1482                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1483                 f.deSerialize(wrapper_is);
1484
1485                 // Check error conditions
1486                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1487                         warningstream << "NodeDefManager::deSerialize(): "
1488                                 "not changing builtin node " << i << std::endl;
1489                         continue;
1490                 }
1491                 if (f.name == "") {
1492                         warningstream << "NodeDefManager::deSerialize(): "
1493                                 "received empty name" << std::endl;
1494                         continue;
1495                 }
1496
1497                 // Ignore aliases
1498                 u16 existing_id;
1499                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1500                         warningstream << "NodeDefManager::deSerialize(): "
1501                                 "already defined with different ID: " << f.name << std::endl;
1502                         continue;
1503                 }
1504
1505                 // All is ok, add node definition with the requested ID
1506                 if (i >= m_content_features.size())
1507                         m_content_features.resize((u32)(i) + 1);
1508                 m_content_features[i] = f;
1509                 addNameIdMapping(i, f.name);
1510                 verbosestream << "deserialized " << f.name << std::endl;
1511
1512                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1513                 fixSelectionBoxIntUnion();
1514         }
1515 }
1516
1517
1518 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1519 {
1520         m_name_id_mapping.set(i, name);
1521         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1522 }
1523
1524
1525 IWritableNodeDefManager *createNodeDefManager()
1526 {
1527         return new CNodeDefManager();
1528 }
1529
1530
1531 //// Serialization of old ContentFeatures formats
1532 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1533 {
1534         u8 compatible_param_type_2 = param_type_2;
1535         if ((protocol_version < 28)
1536                         && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1537                 compatible_param_type_2 = CPT2_NONE;
1538         else if (protocol_version < 30) {
1539                 if (compatible_param_type_2 == CPT2_COLOR)
1540                         compatible_param_type_2 = CPT2_NONE;
1541                 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1542                         compatible_param_type_2 = CPT2_FACEDIR;
1543                 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1544                         compatible_param_type_2 = CPT2_WALLMOUNTED;
1545         }
1546
1547         float compatible_visual_scale = visual_scale;
1548         if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1549                 compatible_visual_scale = sqrt(visual_scale);
1550
1551         TileDef compatible_tiles[6];
1552         for (u8 i = 0; i < 6; i++) {
1553                 compatible_tiles[i] = tiledef[i];
1554                 if (tiledef_overlay[i].name != "") {
1555                         std::stringstream s;
1556                         s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
1557                                 << ")";
1558                         compatible_tiles[i].name = s.str();
1559                 }
1560         }
1561
1562         // Protocol >= 24
1563         if (protocol_version < 31) {
1564                 writeU8(os, protocol_version < 27 ? 7 : 8);
1565
1566                 os << serializeString(name);
1567                 writeU16(os, groups.size());
1568                 for (ItemGroupList::const_iterator i = groups.begin();
1569                                 i != groups.end(); ++i) {
1570                         os << serializeString(i->first);
1571                         writeS16(os, i->second);
1572                 }
1573                 writeU8(os, drawtype);
1574                 writeF1000(os, compatible_visual_scale);
1575                 writeU8(os, 6);
1576                 for (u32 i = 0; i < 6; i++)
1577                         compatible_tiles[i].serialize(os, protocol_version);
1578                 writeU8(os, CF_SPECIAL_COUNT);
1579                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1580                         tiledef_special[i].serialize(os, protocol_version);
1581                 writeU8(os, alpha);
1582                 writeU8(os, post_effect_color.getAlpha());
1583                 writeU8(os, post_effect_color.getRed());
1584                 writeU8(os, post_effect_color.getGreen());
1585                 writeU8(os, post_effect_color.getBlue());
1586                 writeU8(os, param_type);
1587                 writeU8(os, compatible_param_type_2);
1588                 writeU8(os, is_ground_content);
1589                 writeU8(os, light_propagates);
1590                 writeU8(os, sunlight_propagates);
1591                 writeU8(os, walkable);
1592                 writeU8(os, pointable);
1593                 writeU8(os, diggable);
1594                 writeU8(os, climbable);
1595                 writeU8(os, buildable_to);
1596                 os << serializeString(""); // legacy: used to be metadata_name
1597                 writeU8(os, liquid_type);
1598                 os << serializeString(liquid_alternative_flowing);
1599                 os << serializeString(liquid_alternative_source);
1600                 writeU8(os, liquid_viscosity);
1601                 writeU8(os, liquid_renewable);
1602                 writeU8(os, light_source);
1603                 writeU32(os, damage_per_second);
1604                 node_box.serialize(os, protocol_version);
1605                 selection_box.serialize(os, protocol_version);
1606                 writeU8(os, legacy_facedir_simple);
1607                 writeU8(os, legacy_wallmounted);
1608                 serializeSimpleSoundSpec(sound_footstep, os);
1609                 serializeSimpleSoundSpec(sound_dig, os);
1610                 serializeSimpleSoundSpec(sound_dug, os);
1611                 writeU8(os, rightclickable);
1612                 writeU8(os, drowning);
1613                 writeU8(os, leveled);
1614                 writeU8(os, liquid_range);
1615                 writeU8(os, waving);
1616                 os << serializeString(mesh);
1617                 collision_box.serialize(os, protocol_version);
1618                 writeU8(os, floodable);
1619                 writeU16(os, connects_to_ids.size());
1620                 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1621                                 i != connects_to_ids.end(); ++i)
1622                         writeU16(os, *i);
1623                 writeU8(os, connect_sides);
1624         } else {
1625                 throw SerializationError("ContentFeatures::serialize(): "
1626                         "Unsupported version requested");
1627         }
1628 }
1629
1630 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1631 {
1632         if (version == 5) // In PROTOCOL_VERSION 13
1633         {
1634                 name = deSerializeString(is);
1635                 groups.clear();
1636                 u32 groups_size = readU16(is);
1637                 for(u32 i=0; i<groups_size; i++){
1638                         std::string name = deSerializeString(is);
1639                         int value = readS16(is);
1640                         groups[name] = value;
1641                 }
1642                 drawtype = (enum NodeDrawType)readU8(is);
1643
1644                 visual_scale = readF1000(is);
1645                 if (readU8(is) != 6)
1646                         throw SerializationError("unsupported tile count");
1647                 for (u32 i = 0; i < 6; i++)
1648                         tiledef[i].deSerialize(is, version, drawtype);
1649                 if (readU8(is) != CF_SPECIAL_COUNT)
1650                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1651                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1652                         tiledef_special[i].deSerialize(is, version, drawtype);
1653                 alpha = readU8(is);
1654                 post_effect_color.setAlpha(readU8(is));
1655                 post_effect_color.setRed(readU8(is));
1656                 post_effect_color.setGreen(readU8(is));
1657                 post_effect_color.setBlue(readU8(is));
1658                 param_type = (enum ContentParamType)readU8(is);
1659                 param_type_2 = (enum ContentParamType2)readU8(is);
1660                 is_ground_content = readU8(is);
1661                 light_propagates = readU8(is);
1662                 sunlight_propagates = readU8(is);
1663                 walkable = readU8(is);
1664                 pointable = readU8(is);
1665                 diggable = readU8(is);
1666                 climbable = readU8(is);
1667                 buildable_to = readU8(is);
1668                 deSerializeString(is); // legacy: used to be metadata_name
1669                 liquid_type = (enum LiquidType)readU8(is);
1670                 liquid_alternative_flowing = deSerializeString(is);
1671                 liquid_alternative_source = deSerializeString(is);
1672                 liquid_viscosity = readU8(is);
1673                 light_source = readU8(is);
1674                 light_source = MYMIN(light_source, LIGHT_MAX);
1675                 damage_per_second = readU32(is);
1676                 node_box.deSerialize(is);
1677                 selection_box.deSerialize(is);
1678                 legacy_facedir_simple = readU8(is);
1679                 legacy_wallmounted = readU8(is);
1680                 deSerializeSimpleSoundSpec(sound_footstep, is);
1681                 deSerializeSimpleSoundSpec(sound_dig, is);
1682                 deSerializeSimpleSoundSpec(sound_dug, is);
1683         } else if (version == 6) {
1684                 name = deSerializeString(is);
1685                 groups.clear();
1686                 u32 groups_size = readU16(is);
1687                 for (u32 i = 0; i < groups_size; i++) {
1688                         std::string name = deSerializeString(is);
1689                         int     value = readS16(is);
1690                         groups[name] = value;
1691                 }
1692                 drawtype = (enum NodeDrawType)readU8(is);
1693                 visual_scale = readF1000(is);
1694                 if (readU8(is) != 6)
1695                         throw SerializationError("unsupported tile count");
1696                 for (u32 i = 0; i < 6; i++)
1697                         tiledef[i].deSerialize(is, version, drawtype);
1698                 // CF_SPECIAL_COUNT in version 6 = 2
1699                 if (readU8(is) != 2)
1700                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1701                 for (u32 i = 0; i < 2; i++)
1702                         tiledef_special[i].deSerialize(is, version, drawtype);
1703                 alpha = readU8(is);
1704                 post_effect_color.setAlpha(readU8(is));
1705                 post_effect_color.setRed(readU8(is));
1706                 post_effect_color.setGreen(readU8(is));
1707                 post_effect_color.setBlue(readU8(is));
1708                 param_type = (enum ContentParamType)readU8(is);
1709                 param_type_2 = (enum ContentParamType2)readU8(is);
1710                 is_ground_content = readU8(is);
1711                 light_propagates = readU8(is);
1712                 sunlight_propagates = readU8(is);
1713                 walkable = readU8(is);
1714                 pointable = readU8(is);
1715                 diggable = readU8(is);
1716                 climbable = readU8(is);
1717                 buildable_to = readU8(is);
1718                 deSerializeString(is); // legacy: used to be metadata_name
1719                 liquid_type = (enum LiquidType)readU8(is);
1720                 liquid_alternative_flowing = deSerializeString(is);
1721                 liquid_alternative_source = deSerializeString(is);
1722                 liquid_viscosity = readU8(is);
1723                 liquid_renewable = readU8(is);
1724                 light_source = readU8(is);
1725                 damage_per_second = readU32(is);
1726                 node_box.deSerialize(is);
1727                 selection_box.deSerialize(is);
1728                 legacy_facedir_simple = readU8(is);
1729                 legacy_wallmounted = readU8(is);
1730                 deSerializeSimpleSoundSpec(sound_footstep, is);
1731                 deSerializeSimpleSoundSpec(sound_dig, is);
1732                 deSerializeSimpleSoundSpec(sound_dug, is);
1733                 rightclickable = readU8(is);
1734                 drowning = readU8(is);
1735                 leveled = readU8(is);
1736                 liquid_range = readU8(is);
1737         } else if (version == 7 || version == 8){
1738                 name = deSerializeString(is);
1739                 groups.clear();
1740                 u32 groups_size = readU16(is);
1741                 for (u32 i = 0; i < groups_size; i++) {
1742                         std::string name = deSerializeString(is);
1743                         int value = readS16(is);
1744                         groups[name] = value;
1745                 }
1746                 drawtype = (enum NodeDrawType) readU8(is);
1747
1748                 visual_scale = readF1000(is);
1749                 if (readU8(is) != 6)
1750                         throw SerializationError("unsupported tile count");
1751                 for (u32 i = 0; i < 6; i++)
1752                         tiledef[i].deSerialize(is, version, drawtype);
1753                 if (readU8(is) != CF_SPECIAL_COUNT)
1754                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1755                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1756                         tiledef_special[i].deSerialize(is, version, drawtype);
1757                 alpha = readU8(is);
1758                 post_effect_color.setAlpha(readU8(is));
1759                 post_effect_color.setRed(readU8(is));
1760                 post_effect_color.setGreen(readU8(is));
1761                 post_effect_color.setBlue(readU8(is));
1762                 param_type = (enum ContentParamType) readU8(is);
1763                 param_type_2 = (enum ContentParamType2) readU8(is);
1764                 is_ground_content = readU8(is);
1765                 light_propagates = readU8(is);
1766                 sunlight_propagates = readU8(is);
1767                 walkable = readU8(is);
1768                 pointable = readU8(is);
1769                 diggable = readU8(is);
1770                 climbable = readU8(is);
1771                 buildable_to = readU8(is);
1772                 deSerializeString(is); // legacy: used to be metadata_name
1773                 liquid_type = (enum LiquidType) readU8(is);
1774                 liquid_alternative_flowing = deSerializeString(is);
1775                 liquid_alternative_source = deSerializeString(is);
1776                 liquid_viscosity = readU8(is);
1777                 liquid_renewable = readU8(is);
1778                 light_source = readU8(is);
1779                 light_source = MYMIN(light_source, LIGHT_MAX);
1780                 damage_per_second = readU32(is);
1781                 node_box.deSerialize(is);
1782                 selection_box.deSerialize(is);
1783                 legacy_facedir_simple = readU8(is);
1784                 legacy_wallmounted = readU8(is);
1785                 deSerializeSimpleSoundSpec(sound_footstep, is);
1786                 deSerializeSimpleSoundSpec(sound_dig, is);
1787                 deSerializeSimpleSoundSpec(sound_dug, is);
1788                 rightclickable = readU8(is);
1789                 drowning = readU8(is);
1790                 leveled = readU8(is);
1791                 liquid_range = readU8(is);
1792                 waving = readU8(is);
1793                 try {
1794                         mesh = deSerializeString(is);
1795                         collision_box.deSerialize(is);
1796                         floodable = readU8(is);
1797                         u16 connects_to_size = readU16(is);
1798                         connects_to_ids.clear();
1799                         for (u16 i = 0; i < connects_to_size; i++)
1800                                 connects_to_ids.insert(readU16(is));
1801                         connect_sides = readU8(is);
1802                 } catch (SerializationError &e) {};
1803         }else{
1804                 throw SerializationError("unsupported ContentFeatures version");
1805         }
1806 }
1807
1808
1809 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1810 {
1811         return m_node_registration_complete;
1812 }
1813
1814
1815 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1816 {
1817         m_node_registration_complete = completed;
1818 }
1819
1820
1821 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1822 {
1823         nr->m_ndef = this;
1824         if (m_node_registration_complete)
1825                 nr->nodeResolveInternal();
1826         else
1827                 m_pending_resolve_callbacks.push_back(nr);
1828 }
1829
1830
1831 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1832 {
1833         size_t len = m_pending_resolve_callbacks.size();
1834         for (size_t i = 0; i != len; i++) {
1835                 if (nr != m_pending_resolve_callbacks[i])
1836                         continue;
1837
1838                 len--;
1839                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1840                 m_pending_resolve_callbacks.resize(len);
1841                 return true;
1842         }
1843
1844         return false;
1845 }
1846
1847
1848 void CNodeDefManager::runNodeResolveCallbacks()
1849 {
1850         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1851                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1852                 nr->nodeResolveInternal();
1853         }
1854
1855         m_pending_resolve_callbacks.clear();
1856 }
1857
1858
1859 void CNodeDefManager::resetNodeResolveState()
1860 {
1861         m_node_registration_complete = false;
1862         m_pending_resolve_callbacks.clear();
1863 }
1864
1865 void CNodeDefManager::mapNodeboxConnections()
1866 {
1867         for (u32 i = 0; i < m_content_features.size(); i++) {
1868                 ContentFeatures *f = &m_content_features[i];
1869                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1870                         continue;
1871                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1872                                 it != f->connects_to.end(); ++it) {
1873                         getIds(*it, f->connects_to_ids);
1874                 }
1875         }
1876 }
1877
1878 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1879 {
1880         const ContentFeatures &f1 = get(from);
1881
1882         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1883                 return false;
1884
1885         // lookup target in connected set
1886         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1887                 return false;
1888
1889         const ContentFeatures &f2 = get(to);
1890
1891         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1892                 // ignores actually looking if back connection exists
1893                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1894
1895         // does to node declare usable faces?
1896         if (f2.connect_sides > 0) {
1897                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1898                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1899                                 && (connect_face >= 4)) {
1900                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1901                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1902                                 0, // 4 - back
1903                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1904                                 0, // 8 - right
1905                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1906                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1907                                 0, // 16 - front
1908                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1909                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1910                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1911                                 };
1912                         return (f2.connect_sides
1913                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1914                 }
1915                 return (f2.connect_sides & connect_face);
1916         }
1917         // the target is just a regular node, so connect no matter back connection
1918         return true;
1919 }
1920
1921 ////
1922 //// NodeResolver
1923 ////
1924
1925 NodeResolver::NodeResolver()
1926 {
1927         m_ndef            = NULL;
1928         m_nodenames_idx   = 0;
1929         m_nnlistsizes_idx = 0;
1930         m_resolve_done    = false;
1931
1932         m_nodenames.reserve(16);
1933         m_nnlistsizes.reserve(4);
1934 }
1935
1936
1937 NodeResolver::~NodeResolver()
1938 {
1939         if (!m_resolve_done && m_ndef)
1940                 m_ndef->cancelNodeResolveCallback(this);
1941 }
1942
1943
1944 void NodeResolver::nodeResolveInternal()
1945 {
1946         m_nodenames_idx   = 0;
1947         m_nnlistsizes_idx = 0;
1948
1949         resolveNodeNames();
1950         m_resolve_done = true;
1951
1952         m_nodenames.clear();
1953         m_nnlistsizes.clear();
1954 }
1955
1956
1957 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1958         const std::string &node_alt, content_t c_fallback)
1959 {
1960         if (m_nodenames_idx == m_nodenames.size()) {
1961                 *result_out = c_fallback;
1962                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1963                 return false;
1964         }
1965
1966         content_t c;
1967         std::string name = m_nodenames[m_nodenames_idx++];
1968
1969         bool success = m_ndef->getId(name, c);
1970         if (!success && node_alt != "") {
1971                 name = node_alt;
1972                 success = m_ndef->getId(name, c);
1973         }
1974
1975         if (!success) {
1976                 errorstream << "NodeResolver: failed to resolve node name '" << name
1977                         << "'." << std::endl;
1978                 c = c_fallback;
1979         }
1980
1981         *result_out = c;
1982         return success;
1983 }
1984
1985
1986 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1987         bool all_required, content_t c_fallback)
1988 {
1989         bool success = true;
1990
1991         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1992                 errorstream << "NodeResolver: no more node lists" << std::endl;
1993                 return false;
1994         }
1995
1996         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1997
1998         while (length--) {
1999                 if (m_nodenames_idx == m_nodenames.size()) {
2000                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
2001                         return false;
2002                 }
2003
2004                 content_t c;
2005                 std::string &name = m_nodenames[m_nodenames_idx++];
2006
2007                 if (name.substr(0,6) != "group:") {
2008                         if (m_ndef->getId(name, c)) {
2009                                 result_out->push_back(c);
2010                         } else if (all_required) {
2011                                 errorstream << "NodeResolver: failed to resolve node name '"
2012                                         << name << "'." << std::endl;
2013                                 result_out->push_back(c_fallback);
2014                                 success = false;
2015                         }
2016                 } else {
2017                         std::set<content_t> cids;
2018                         std::set<content_t>::iterator it;
2019                         m_ndef->getIds(name, cids);
2020                         for (it = cids.begin(); it != cids.end(); ++it)
2021                                 result_out->push_back(*it);
2022                 }
2023         }
2024
2025         return success;
2026 }