]> git.lizzy.rs Git - dragonfireclient.git/blob - src/nodedef.cpp
3532eea1e6951686095b17450b9be505c7b102db
[dragonfireclient.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 = idef->getAll();
1336         m_name_id_mapping_with_aliases.clear();
1337         for (std::set<std::string>::iterator
1338                         i = all.begin(); i != all.end(); ++i) {
1339                 std::string name = *i;
1340                 std::string convert_to = idef->getAlias(name);
1341                 content_t id;
1342                 if (m_name_id_mapping.getId(convert_to, id)) {
1343                         m_name_id_mapping_with_aliases.insert(
1344                                 std::make_pair(name, id));
1345                 }
1346         }
1347 }
1348
1349 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1350 {
1351         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1352                 "overrides to textures from " << override_filepath << std::endl;
1353
1354         std::ifstream infile(override_filepath.c_str());
1355         std::string line;
1356         int line_c = 0;
1357         while (std::getline(infile, line)) {
1358                 line_c++;
1359                 if (trim(line) == "")
1360                         continue;
1361                 std::vector<std::string> splitted = str_split(line, ' ');
1362                 if (splitted.size() != 3) {
1363                         errorstream << override_filepath
1364                                 << ":" << line_c << " Could not apply texture override \""
1365                                 << line << "\": Syntax error" << std::endl;
1366                         continue;
1367                 }
1368
1369                 content_t id;
1370                 if (!getId(splitted[0], id))
1371                         continue; // Ignore unknown node
1372
1373                 ContentFeatures &nodedef = m_content_features[id];
1374
1375                 if (splitted[1] == "top")
1376                         nodedef.tiledef[0].name = splitted[2];
1377                 else if (splitted[1] == "bottom")
1378                         nodedef.tiledef[1].name = splitted[2];
1379                 else if (splitted[1] == "right")
1380                         nodedef.tiledef[2].name = splitted[2];
1381                 else if (splitted[1] == "left")
1382                         nodedef.tiledef[3].name = splitted[2];
1383                 else if (splitted[1] == "back")
1384                         nodedef.tiledef[4].name = splitted[2];
1385                 else if (splitted[1] == "front")
1386                         nodedef.tiledef[5].name = splitted[2];
1387                 else if (splitted[1] == "all" || splitted[1] == "*")
1388                         for (int i = 0; i < 6; i++)
1389                                 nodedef.tiledef[i].name = splitted[2];
1390                 else if (splitted[1] == "sides")
1391                         for (int i = 2; i < 6; i++)
1392                                 nodedef.tiledef[i].name = splitted[2];
1393                 else {
1394                         errorstream << override_filepath
1395                                 << ":" << line_c << " Could not apply texture override \""
1396                                 << line << "\": Unknown node side \""
1397                                 << splitted[1] << "\"" << std::endl;
1398                         continue;
1399                 }
1400         }
1401 }
1402
1403 std::vector<video::SColor> *CNodeDefManager::getPalette(
1404         const ContentFeatures &f, const IGameDef *gamedef)
1405 {
1406 #ifndef SERVER
1407         // This works because colors always use the most significant bits
1408         // of param2. If you add a new colored type which uses param2
1409         // in a more advanced way, you should change this code, too.
1410         u32 palette_pixels = 0;
1411         switch (f.param_type_2) {
1412                 case CPT2_COLOR:
1413                         palette_pixels = 256;
1414                         break;
1415                 case CPT2_COLORED_FACEDIR:
1416                         palette_pixels = 8;
1417                         break;
1418                 case CPT2_COLORED_WALLMOUNTED:
1419                         palette_pixels = 32;
1420                         break;
1421                 default:
1422                         return NULL;
1423         }
1424         // This many param2 values will have the same color
1425         u32 step = 256 / palette_pixels;
1426         const std::string &name = f.palette_name;
1427         if (name == "")
1428                 return NULL;
1429         Client *client = (Client *) gamedef;
1430         ITextureSource *tsrc = client->tsrc();
1431
1432         UNORDERED_MAP<std::string, std::vector<video::SColor> >::iterator it =
1433         m_palettes.find(name);
1434         if (it == m_palettes.end()) {
1435                 // Create palette
1436                 if (!tsrc->isKnownSourceImage(name)) {
1437                         warningstream << "CNodeDefManager::getPalette(): palette \"" << name
1438                                 << "\" could not be loaded." << std::endl;
1439                         return NULL;
1440                 }
1441                 video::IImage *img = tsrc->generateImage(name);
1442                 std::vector<video::SColor> new_palette;
1443                 u32 w = img->getDimension().Width;
1444                 u32 h = img->getDimension().Height;
1445                 // Real area of the image
1446                 u32 area = h * w;
1447                 if (area != palette_pixels)
1448                         warningstream << "CNodeDefManager::getPalette(): the "
1449                                 << "specified palette image \"" << name << "\" does not "
1450                                 << "contain exactly " << palette_pixels
1451                                 << " pixels." << std::endl;
1452                 if (area > palette_pixels)
1453                         area = palette_pixels;
1454                 // For each pixel in the image
1455                 for (u32 i = 0; i < area; i++) {
1456                         video::SColor c = img->getPixel(i % w, i / w);
1457                         // Fill in palette with 'step' colors
1458                         for (u32 j = 0; j < step; j++)
1459                                 new_palette.push_back(c);
1460                 }
1461                 img->drop();
1462                 // Fill in remaining elements
1463                 while (new_palette.size() < 256)
1464                         new_palette.push_back(video::SColor(0xFFFFFFFF));
1465                 m_palettes[name] = new_palette;
1466                 it = m_palettes.find(name);
1467         }
1468         if (it != m_palettes.end())
1469                 return &((*it).second);
1470
1471 #endif
1472         return NULL;
1473 }
1474
1475 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1476         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1477         void *progress_callback_args)
1478 {
1479 #ifndef SERVER
1480         infostream << "CNodeDefManager::updateTextures(): Updating "
1481                 "textures in node definitions" << std::endl;
1482
1483         Client *client = (Client *)gamedef;
1484         ITextureSource *tsrc = client->tsrc();
1485         IShaderSource *shdsrc = client->getShaderSource();
1486         scene::ISceneManager* smgr = client->getSceneManager();
1487         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1488         TextureSettings tsettings;
1489         tsettings.readSettings();
1490
1491         m_palettes.clear();
1492         u32 size = m_content_features.size();
1493
1494         for (u32 i = 0; i < size; i++) {
1495                 ContentFeatures *f = &(m_content_features[i]);
1496                 f->palette = getPalette(*f, gamedef);
1497                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1498                 progress_callback(progress_callback_args, i, size);
1499         }
1500 #endif
1501 }
1502
1503 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1504 {
1505         writeU8(os, 1); // version
1506         u16 count = 0;
1507         std::ostringstream os2(std::ios::binary);
1508         for (u32 i = 0; i < m_content_features.size(); i++) {
1509                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1510                                 || i == CONTENT_UNKNOWN)
1511                         continue;
1512                 const ContentFeatures *f = &m_content_features[i];
1513                 if (f->name == "")
1514                         continue;
1515                 writeU16(os2, i);
1516                 // Wrap it in a string to allow different lengths without
1517                 // strict version incompatibilities
1518                 std::ostringstream wrapper_os(std::ios::binary);
1519                 f->serialize(wrapper_os, protocol_version);
1520                 os2<<serializeString(wrapper_os.str());
1521
1522                 // must not overflow
1523                 u16 next = count + 1;
1524                 FATAL_ERROR_IF(next < count, "Overflow");
1525                 count++;
1526         }
1527         writeU16(os, count);
1528         os << serializeLongString(os2.str());
1529 }
1530
1531
1532 void CNodeDefManager::deSerialize(std::istream &is)
1533 {
1534         clear();
1535         int version = readU8(is);
1536         if (version != 1)
1537                 throw SerializationError("unsupported NodeDefinitionManager version");
1538         u16 count = readU16(is);
1539         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1540         ContentFeatures f;
1541         for (u16 n = 0; n < count; n++) {
1542                 u16 i = readU16(is2);
1543
1544                 // Read it from the string wrapper
1545                 std::string wrapper = deSerializeString(is2);
1546                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1547                 f.deSerialize(wrapper_is);
1548
1549                 // Check error conditions
1550                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1551                         warningstream << "NodeDefManager::deSerialize(): "
1552                                 "not changing builtin node " << i << std::endl;
1553                         continue;
1554                 }
1555                 if (f.name == "") {
1556                         warningstream << "NodeDefManager::deSerialize(): "
1557                                 "received empty name" << std::endl;
1558                         continue;
1559                 }
1560
1561                 // Ignore aliases
1562                 u16 existing_id;
1563                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1564                         warningstream << "NodeDefManager::deSerialize(): "
1565                                 "already defined with different ID: " << f.name << std::endl;
1566                         continue;
1567                 }
1568
1569                 // All is ok, add node definition with the requested ID
1570                 if (i >= m_content_features.size())
1571                         m_content_features.resize((u32)(i) + 1);
1572                 m_content_features[i] = f;
1573                 addNameIdMapping(i, f.name);
1574                 verbosestream << "deserialized " << f.name << std::endl;
1575
1576                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1577                 fixSelectionBoxIntUnion();
1578         }
1579 }
1580
1581
1582 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1583 {
1584         m_name_id_mapping.set(i, name);
1585         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1586 }
1587
1588
1589 IWritableNodeDefManager *createNodeDefManager()
1590 {
1591         return new CNodeDefManager();
1592 }
1593
1594
1595 //// Serialization of old ContentFeatures formats
1596 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1597 {
1598         u8 compatible_param_type_2 = param_type_2;
1599         if ((protocol_version < 28)
1600                         && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1601                 compatible_param_type_2 = CPT2_NONE;
1602         else if (protocol_version < 30) {
1603                 if (compatible_param_type_2 == CPT2_COLOR)
1604                         compatible_param_type_2 = CPT2_NONE;
1605                 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1606                         compatible_param_type_2 = CPT2_FACEDIR;
1607                 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1608                         compatible_param_type_2 = CPT2_WALLMOUNTED;
1609         }
1610
1611         float compatible_visual_scale = visual_scale;
1612         if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1613                 compatible_visual_scale = sqrt(visual_scale);
1614
1615         // Protocol >= 24
1616         if (protocol_version < 30) {
1617                 writeU8(os, protocol_version < 27 ? 7 : 8);
1618
1619                 os << serializeString(name);
1620                 writeU16(os, groups.size());
1621                 for (ItemGroupList::const_iterator i = groups.begin();
1622                                 i != groups.end(); ++i) {
1623                         os << serializeString(i->first);
1624                         writeS16(os, i->second);
1625                 }
1626                 writeU8(os, drawtype);
1627                 writeF1000(os, compatible_visual_scale);
1628                 writeU8(os, 6);
1629                 for (u32 i = 0; i < 6; i++)
1630                         tiledef[i].serialize(os, protocol_version);
1631                 writeU8(os, CF_SPECIAL_COUNT);
1632                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1633                         tiledef_special[i].serialize(os, protocol_version);
1634                 writeU8(os, alpha);
1635                 writeU8(os, post_effect_color.getAlpha());
1636                 writeU8(os, post_effect_color.getRed());
1637                 writeU8(os, post_effect_color.getGreen());
1638                 writeU8(os, post_effect_color.getBlue());
1639                 writeU8(os, param_type);
1640                 writeU8(os, compatible_param_type_2);
1641                 writeU8(os, is_ground_content);
1642                 writeU8(os, light_propagates);
1643                 writeU8(os, sunlight_propagates);
1644                 writeU8(os, walkable);
1645                 writeU8(os, pointable);
1646                 writeU8(os, diggable);
1647                 writeU8(os, climbable);
1648                 writeU8(os, buildable_to);
1649                 os << serializeString(""); // legacy: used to be metadata_name
1650                 writeU8(os, liquid_type);
1651                 os << serializeString(liquid_alternative_flowing);
1652                 os << serializeString(liquid_alternative_source);
1653                 writeU8(os, liquid_viscosity);
1654                 writeU8(os, liquid_renewable);
1655                 writeU8(os, light_source);
1656                 writeU32(os, damage_per_second);
1657                 node_box.serialize(os, protocol_version);
1658                 selection_box.serialize(os, protocol_version);
1659                 writeU8(os, legacy_facedir_simple);
1660                 writeU8(os, legacy_wallmounted);
1661                 serializeSimpleSoundSpec(sound_footstep, os);
1662                 serializeSimpleSoundSpec(sound_dig, os);
1663                 serializeSimpleSoundSpec(sound_dug, os);
1664                 writeU8(os, rightclickable);
1665                 writeU8(os, drowning);
1666                 writeU8(os, leveled);
1667                 writeU8(os, liquid_range);
1668                 writeU8(os, waving);
1669                 os << serializeString(mesh);
1670                 collision_box.serialize(os, protocol_version);
1671                 writeU8(os, floodable);
1672                 writeU16(os, connects_to_ids.size());
1673                 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1674                                 i != connects_to_ids.end(); ++i)
1675                         writeU16(os, *i);
1676                 writeU8(os, connect_sides);
1677         } else {
1678                 throw SerializationError("ContentFeatures::serialize(): "
1679                         "Unsupported version requested");
1680         }
1681 }
1682
1683 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1684 {
1685         if (version == 5) // In PROTOCOL_VERSION 13
1686         {
1687                 name = deSerializeString(is);
1688                 groups.clear();
1689                 u32 groups_size = readU16(is);
1690                 for(u32 i=0; i<groups_size; i++){
1691                         std::string name = deSerializeString(is);
1692                         int value = readS16(is);
1693                         groups[name] = value;
1694                 }
1695                 drawtype = (enum NodeDrawType)readU8(is);
1696
1697                 visual_scale = readF1000(is);
1698                 if (readU8(is) != 6)
1699                         throw SerializationError("unsupported tile count");
1700                 for (u32 i = 0; i < 6; i++)
1701                         tiledef[i].deSerialize(is, version, drawtype);
1702                 if (readU8(is) != CF_SPECIAL_COUNT)
1703                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1704                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1705                         tiledef_special[i].deSerialize(is, version, drawtype);
1706                 alpha = readU8(is);
1707                 post_effect_color.setAlpha(readU8(is));
1708                 post_effect_color.setRed(readU8(is));
1709                 post_effect_color.setGreen(readU8(is));
1710                 post_effect_color.setBlue(readU8(is));
1711                 param_type = (enum ContentParamType)readU8(is);
1712                 param_type_2 = (enum ContentParamType2)readU8(is);
1713                 is_ground_content = readU8(is);
1714                 light_propagates = readU8(is);
1715                 sunlight_propagates = readU8(is);
1716                 walkable = readU8(is);
1717                 pointable = readU8(is);
1718                 diggable = readU8(is);
1719                 climbable = readU8(is);
1720                 buildable_to = readU8(is);
1721                 deSerializeString(is); // legacy: used to be metadata_name
1722                 liquid_type = (enum LiquidType)readU8(is);
1723                 liquid_alternative_flowing = deSerializeString(is);
1724                 liquid_alternative_source = deSerializeString(is);
1725                 liquid_viscosity = readU8(is);
1726                 light_source = readU8(is);
1727                 light_source = MYMIN(light_source, LIGHT_MAX);
1728                 damage_per_second = readU32(is);
1729                 node_box.deSerialize(is);
1730                 selection_box.deSerialize(is);
1731                 legacy_facedir_simple = readU8(is);
1732                 legacy_wallmounted = readU8(is);
1733                 deSerializeSimpleSoundSpec(sound_footstep, is);
1734                 deSerializeSimpleSoundSpec(sound_dig, is);
1735                 deSerializeSimpleSoundSpec(sound_dug, is);
1736         } else if (version == 6) {
1737                 name = deSerializeString(is);
1738                 groups.clear();
1739                 u32 groups_size = readU16(is);
1740                 for (u32 i = 0; i < groups_size; i++) {
1741                         std::string name = deSerializeString(is);
1742                         int     value = readS16(is);
1743                         groups[name] = value;
1744                 }
1745                 drawtype = (enum NodeDrawType)readU8(is);
1746                 visual_scale = readF1000(is);
1747                 if (readU8(is) != 6)
1748                         throw SerializationError("unsupported tile count");
1749                 for (u32 i = 0; i < 6; i++)
1750                         tiledef[i].deSerialize(is, version, drawtype);
1751                 // CF_SPECIAL_COUNT in version 6 = 2
1752                 if (readU8(is) != 2)
1753                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1754                 for (u32 i = 0; i < 2; i++)
1755                         tiledef_special[i].deSerialize(is, version, drawtype);
1756                 alpha = readU8(is);
1757                 post_effect_color.setAlpha(readU8(is));
1758                 post_effect_color.setRed(readU8(is));
1759                 post_effect_color.setGreen(readU8(is));
1760                 post_effect_color.setBlue(readU8(is));
1761                 param_type = (enum ContentParamType)readU8(is);
1762                 param_type_2 = (enum ContentParamType2)readU8(is);
1763                 is_ground_content = readU8(is);
1764                 light_propagates = readU8(is);
1765                 sunlight_propagates = readU8(is);
1766                 walkable = readU8(is);
1767                 pointable = readU8(is);
1768                 diggable = readU8(is);
1769                 climbable = readU8(is);
1770                 buildable_to = readU8(is);
1771                 deSerializeString(is); // legacy: used to be metadata_name
1772                 liquid_type = (enum LiquidType)readU8(is);
1773                 liquid_alternative_flowing = deSerializeString(is);
1774                 liquid_alternative_source = deSerializeString(is);
1775                 liquid_viscosity = readU8(is);
1776                 liquid_renewable = readU8(is);
1777                 light_source = readU8(is);
1778                 damage_per_second = readU32(is);
1779                 node_box.deSerialize(is);
1780                 selection_box.deSerialize(is);
1781                 legacy_facedir_simple = readU8(is);
1782                 legacy_wallmounted = readU8(is);
1783                 deSerializeSimpleSoundSpec(sound_footstep, is);
1784                 deSerializeSimpleSoundSpec(sound_dig, is);
1785                 deSerializeSimpleSoundSpec(sound_dug, is);
1786                 rightclickable = readU8(is);
1787                 drowning = readU8(is);
1788                 leveled = readU8(is);
1789                 liquid_range = readU8(is);
1790         } else if (version == 7 || version == 8){
1791                 name = deSerializeString(is);
1792                 groups.clear();
1793                 u32 groups_size = readU16(is);
1794                 for (u32 i = 0; i < groups_size; i++) {
1795                         std::string name = deSerializeString(is);
1796                         int value = readS16(is);
1797                         groups[name] = value;
1798                 }
1799                 drawtype = (enum NodeDrawType) readU8(is);
1800
1801                 visual_scale = readF1000(is);
1802                 if (readU8(is) != 6)
1803                         throw SerializationError("unsupported tile count");
1804                 for (u32 i = 0; i < 6; i++)
1805                         tiledef[i].deSerialize(is, version, drawtype);
1806                 if (readU8(is) != CF_SPECIAL_COUNT)
1807                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1808                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1809                         tiledef_special[i].deSerialize(is, version, drawtype);
1810                 alpha = readU8(is);
1811                 post_effect_color.setAlpha(readU8(is));
1812                 post_effect_color.setRed(readU8(is));
1813                 post_effect_color.setGreen(readU8(is));
1814                 post_effect_color.setBlue(readU8(is));
1815                 param_type = (enum ContentParamType) readU8(is);
1816                 param_type_2 = (enum ContentParamType2) readU8(is);
1817                 is_ground_content = readU8(is);
1818                 light_propagates = readU8(is);
1819                 sunlight_propagates = readU8(is);
1820                 walkable = readU8(is);
1821                 pointable = readU8(is);
1822                 diggable = readU8(is);
1823                 climbable = readU8(is);
1824                 buildable_to = readU8(is);
1825                 deSerializeString(is); // legacy: used to be metadata_name
1826                 liquid_type = (enum LiquidType) readU8(is);
1827                 liquid_alternative_flowing = deSerializeString(is);
1828                 liquid_alternative_source = deSerializeString(is);
1829                 liquid_viscosity = readU8(is);
1830                 liquid_renewable = readU8(is);
1831                 light_source = readU8(is);
1832                 light_source = MYMIN(light_source, LIGHT_MAX);
1833                 damage_per_second = readU32(is);
1834                 node_box.deSerialize(is);
1835                 selection_box.deSerialize(is);
1836                 legacy_facedir_simple = readU8(is);
1837                 legacy_wallmounted = readU8(is);
1838                 deSerializeSimpleSoundSpec(sound_footstep, is);
1839                 deSerializeSimpleSoundSpec(sound_dig, is);
1840                 deSerializeSimpleSoundSpec(sound_dug, is);
1841                 rightclickable = readU8(is);
1842                 drowning = readU8(is);
1843                 leveled = readU8(is);
1844                 liquid_range = readU8(is);
1845                 waving = readU8(is);
1846                 try {
1847                         mesh = deSerializeString(is);
1848                         collision_box.deSerialize(is);
1849                         floodable = readU8(is);
1850                         u16 connects_to_size = readU16(is);
1851                         connects_to_ids.clear();
1852                         for (u16 i = 0; i < connects_to_size; i++)
1853                                 connects_to_ids.insert(readU16(is));
1854                         connect_sides = readU8(is);
1855                 } catch (SerializationError &e) {};
1856         }else{
1857                 throw SerializationError("unsupported ContentFeatures version");
1858         }
1859 }
1860
1861
1862 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1863 {
1864         return m_node_registration_complete;
1865 }
1866
1867
1868 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1869 {
1870         m_node_registration_complete = completed;
1871 }
1872
1873
1874 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1875 {
1876         nr->m_ndef = this;
1877         if (m_node_registration_complete)
1878                 nr->nodeResolveInternal();
1879         else
1880                 m_pending_resolve_callbacks.push_back(nr);
1881 }
1882
1883
1884 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1885 {
1886         size_t len = m_pending_resolve_callbacks.size();
1887         for (size_t i = 0; i != len; i++) {
1888                 if (nr != m_pending_resolve_callbacks[i])
1889                         continue;
1890
1891                 len--;
1892                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1893                 m_pending_resolve_callbacks.resize(len);
1894                 return true;
1895         }
1896
1897         return false;
1898 }
1899
1900
1901 void CNodeDefManager::runNodeResolveCallbacks()
1902 {
1903         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1904                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1905                 nr->nodeResolveInternal();
1906         }
1907
1908         m_pending_resolve_callbacks.clear();
1909 }
1910
1911
1912 void CNodeDefManager::resetNodeResolveState()
1913 {
1914         m_node_registration_complete = false;
1915         m_pending_resolve_callbacks.clear();
1916 }
1917
1918 void CNodeDefManager::mapNodeboxConnections()
1919 {
1920         for (u32 i = 0; i < m_content_features.size(); i++) {
1921                 ContentFeatures *f = &m_content_features[i];
1922                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1923                         continue;
1924                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1925                                 it != f->connects_to.end(); ++it) {
1926                         getIds(*it, f->connects_to_ids);
1927                 }
1928         }
1929 }
1930
1931 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1932 {
1933         const ContentFeatures &f1 = get(from);
1934
1935         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1936                 return false;
1937
1938         // lookup target in connected set
1939         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1940                 return false;
1941
1942         const ContentFeatures &f2 = get(to);
1943
1944         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1945                 // ignores actually looking if back connection exists
1946                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1947
1948         // does to node declare usable faces?
1949         if (f2.connect_sides > 0) {
1950                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1951                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1952                                 && (connect_face >= 4)) {
1953                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1954                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1955                                 0, // 4 - back
1956                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1957                                 0, // 8 - right
1958                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1959                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1960                                 0, // 16 - front
1961                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 32, 16, 8, 4 // 32 - left
1964                                 };
1965                         return (f2.connect_sides
1966                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1967                 }
1968                 return (f2.connect_sides & connect_face);
1969         }
1970         // the target is just a regular node, so connect no matter back connection
1971         return true;
1972 }
1973
1974 ////
1975 //// NodeResolver
1976 ////
1977
1978 NodeResolver::NodeResolver()
1979 {
1980         m_ndef            = NULL;
1981         m_nodenames_idx   = 0;
1982         m_nnlistsizes_idx = 0;
1983         m_resolve_done    = false;
1984
1985         m_nodenames.reserve(16);
1986         m_nnlistsizes.reserve(4);
1987 }
1988
1989
1990 NodeResolver::~NodeResolver()
1991 {
1992         if (!m_resolve_done && m_ndef)
1993                 m_ndef->cancelNodeResolveCallback(this);
1994 }
1995
1996
1997 void NodeResolver::nodeResolveInternal()
1998 {
1999         m_nodenames_idx   = 0;
2000         m_nnlistsizes_idx = 0;
2001
2002         resolveNodeNames();
2003         m_resolve_done = true;
2004
2005         m_nodenames.clear();
2006         m_nnlistsizes.clear();
2007 }
2008
2009
2010 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
2011         const std::string &node_alt, content_t c_fallback)
2012 {
2013         if (m_nodenames_idx == m_nodenames.size()) {
2014                 *result_out = c_fallback;
2015                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
2016                 return false;
2017         }
2018
2019         content_t c;
2020         std::string name = m_nodenames[m_nodenames_idx++];
2021
2022         bool success = m_ndef->getId(name, c);
2023         if (!success && node_alt != "") {
2024                 name = node_alt;
2025                 success = m_ndef->getId(name, c);
2026         }
2027
2028         if (!success) {
2029                 errorstream << "NodeResolver: failed to resolve node name '" << name
2030                         << "'." << std::endl;
2031                 c = c_fallback;
2032         }
2033
2034         *result_out = c;
2035         return success;
2036 }
2037
2038
2039 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
2040         bool all_required, content_t c_fallback)
2041 {
2042         bool success = true;
2043
2044         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
2045                 errorstream << "NodeResolver: no more node lists" << std::endl;
2046                 return false;
2047         }
2048
2049         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
2050
2051         while (length--) {
2052                 if (m_nodenames_idx == m_nodenames.size()) {
2053                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
2054                         return false;
2055                 }
2056
2057                 content_t c;
2058                 std::string &name = m_nodenames[m_nodenames_idx++];
2059
2060                 if (name.substr(0,6) != "group:") {
2061                         if (m_ndef->getId(name, c)) {
2062                                 result_out->push_back(c);
2063                         } else if (all_required) {
2064                                 errorstream << "NodeResolver: failed to resolve node name '"
2065                                         << name << "'." << std::endl;
2066                                 result_out->push_back(c_fallback);
2067                                 success = false;
2068                         }
2069                 } else {
2070                         std::set<content_t> cids;
2071                         std::set<content_t>::iterator it;
2072                         m_ndef->getIds(name, cids);
2073                         for (it = cids.begin(); it != cids.end(); ++it)
2074                                 result_out->push_back(*it);
2075                 }
2076         }
2077
2078         return success;
2079 }