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