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