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