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