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