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