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