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