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