Revert "Plantlike visual scale: Send sqrt(visual_scale) to old clients"
[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         if (protocol_version == 13)
1615         {
1616                 writeU8(os, 5); // version
1617                 os<<serializeString(name);
1618                 writeU16(os, groups.size());
1619                 for (ItemGroupList::const_iterator
1620                                 i = groups.begin(); i != groups.end(); ++i) {
1621                         os<<serializeString(i->first);
1622                         writeS16(os, i->second);
1623                 }
1624                 writeU8(os, drawtype);
1625                 writeF1000(os, visual_scale);
1626                 writeU8(os, 6);
1627                 for (u32 i = 0; i < 6; i++)
1628                         tiledef[i].serialize(os, protocol_version);
1629                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1630                 writeU8(os, 2);
1631                 for (u32 i = 0; i < 2; i++)
1632                         tiledef_special[i].serialize(os, protocol_version);
1633                 writeU8(os, alpha);
1634                 writeU8(os, post_effect_color.getAlpha());
1635                 writeU8(os, post_effect_color.getRed());
1636                 writeU8(os, post_effect_color.getGreen());
1637                 writeU8(os, post_effect_color.getBlue());
1638                 writeU8(os, param_type);
1639                 writeU8(os, compatible_param_type_2);
1640                 writeU8(os, is_ground_content);
1641                 writeU8(os, light_propagates);
1642                 writeU8(os, sunlight_propagates);
1643                 writeU8(os, walkable);
1644                 writeU8(os, pointable);
1645                 writeU8(os, diggable);
1646                 writeU8(os, climbable);
1647                 writeU8(os, buildable_to);
1648                 os<<serializeString(""); // legacy: used to be metadata_name
1649                 writeU8(os, liquid_type);
1650                 os<<serializeString(liquid_alternative_flowing);
1651                 os<<serializeString(liquid_alternative_source);
1652                 writeU8(os, liquid_viscosity);
1653                 writeU8(os, light_source);
1654                 writeU32(os, damage_per_second);
1655                 node_box.serialize(os, protocol_version);
1656                 selection_box.serialize(os, protocol_version);
1657                 writeU8(os, legacy_facedir_simple);
1658                 writeU8(os, legacy_wallmounted);
1659                 serializeSimpleSoundSpec(sound_footstep, os);
1660                 serializeSimpleSoundSpec(sound_dig, os);
1661                 serializeSimpleSoundSpec(sound_dug, os);
1662         }
1663         else if (protocol_version > 13 && protocol_version < 24) {
1664                 writeU8(os, 6); // version
1665                 os<<serializeString(name);
1666                 writeU16(os, groups.size());
1667                 for (ItemGroupList::const_iterator
1668                                 i = groups.begin(); i != groups.end(); ++i) {
1669                         os<<serializeString(i->first);
1670                         writeS16(os, i->second);
1671                 }
1672                 writeU8(os, drawtype);
1673                 writeF1000(os, visual_scale);
1674                 writeU8(os, 6);
1675                 for (u32 i = 0; i < 6; i++)
1676                         tiledef[i].serialize(os, protocol_version);
1677                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1678                 writeU8(os, 2);
1679                 for (u32 i = 0; i < 2; i++)
1680                         tiledef_special[i].serialize(os, protocol_version);
1681                 writeU8(os, alpha);
1682                 writeU8(os, post_effect_color.getAlpha());
1683                 writeU8(os, post_effect_color.getRed());
1684                 writeU8(os, post_effect_color.getGreen());
1685                 writeU8(os, post_effect_color.getBlue());
1686                 writeU8(os, param_type);
1687                 writeU8(os, compatible_param_type_2);
1688                 writeU8(os, is_ground_content);
1689                 writeU8(os, light_propagates);
1690                 writeU8(os, sunlight_propagates);
1691                 writeU8(os, walkable);
1692                 writeU8(os, pointable);
1693                 writeU8(os, diggable);
1694                 writeU8(os, climbable);
1695                 writeU8(os, buildable_to);
1696                 os<<serializeString(""); // legacy: used to be metadata_name
1697                 writeU8(os, liquid_type);
1698                 os<<serializeString(liquid_alternative_flowing);
1699                 os<<serializeString(liquid_alternative_source);
1700                 writeU8(os, liquid_viscosity);
1701                 writeU8(os, liquid_renewable);
1702                 writeU8(os, light_source);
1703                 writeU32(os, damage_per_second);
1704                 node_box.serialize(os, protocol_version);
1705                 selection_box.serialize(os, protocol_version);
1706                 writeU8(os, legacy_facedir_simple);
1707                 writeU8(os, legacy_wallmounted);
1708                 serializeSimpleSoundSpec(sound_footstep, os);
1709                 serializeSimpleSoundSpec(sound_dig, os);
1710                 serializeSimpleSoundSpec(sound_dug, os);
1711                 writeU8(os, rightclickable);
1712                 writeU8(os, drowning);
1713                 writeU8(os, leveled);
1714                 writeU8(os, liquid_range);
1715         }
1716         else if(protocol_version >= 24 && protocol_version < 30) {
1717                 writeU8(os, protocol_version < 27 ? 7 : 8);
1718
1719                 os << serializeString(name);
1720                 writeU16(os, groups.size());
1721                 for (ItemGroupList::const_iterator i = groups.begin();
1722                                 i != groups.end(); ++i) {
1723                         os << serializeString(i->first);
1724                         writeS16(os, i->second);
1725                 }
1726                 writeU8(os, drawtype);
1727                 writeF1000(os, visual_scale);
1728                 writeU8(os, 6);
1729                 for (u32 i = 0; i < 6; i++)
1730                         tiledef[i].serialize(os, protocol_version);
1731                 writeU8(os, CF_SPECIAL_COUNT);
1732                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1733                         tiledef_special[i].serialize(os, protocol_version);
1734                 writeU8(os, alpha);
1735                 writeU8(os, post_effect_color.getAlpha());
1736                 writeU8(os, post_effect_color.getRed());
1737                 writeU8(os, post_effect_color.getGreen());
1738                 writeU8(os, post_effect_color.getBlue());
1739                 writeU8(os, param_type);
1740                 writeU8(os, compatible_param_type_2);
1741                 writeU8(os, is_ground_content);
1742                 writeU8(os, light_propagates);
1743                 writeU8(os, sunlight_propagates);
1744                 writeU8(os, walkable);
1745                 writeU8(os, pointable);
1746                 writeU8(os, diggable);
1747                 writeU8(os, climbable);
1748                 writeU8(os, buildable_to);
1749                 os << serializeString(""); // legacy: used to be metadata_name
1750                 writeU8(os, liquid_type);
1751                 os << serializeString(liquid_alternative_flowing);
1752                 os << serializeString(liquid_alternative_source);
1753                 writeU8(os, liquid_viscosity);
1754                 writeU8(os, liquid_renewable);
1755                 writeU8(os, light_source);
1756                 writeU32(os, damage_per_second);
1757                 node_box.serialize(os, protocol_version);
1758                 selection_box.serialize(os, protocol_version);
1759                 writeU8(os, legacy_facedir_simple);
1760                 writeU8(os, legacy_wallmounted);
1761                 serializeSimpleSoundSpec(sound_footstep, os);
1762                 serializeSimpleSoundSpec(sound_dig, os);
1763                 serializeSimpleSoundSpec(sound_dug, os);
1764                 writeU8(os, rightclickable);
1765                 writeU8(os, drowning);
1766                 writeU8(os, leveled);
1767                 writeU8(os, liquid_range);
1768                 writeU8(os, waving);
1769                 os << serializeString(mesh);
1770                 collision_box.serialize(os, protocol_version);
1771                 writeU8(os, floodable);
1772                 writeU16(os, connects_to_ids.size());
1773                 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1774                                 i != connects_to_ids.end(); ++i)
1775                         writeU16(os, *i);
1776                 writeU8(os, connect_sides);
1777         } else
1778                 throw SerializationError("ContentFeatures::serialize(): "
1779                         "Unsupported version requested");
1780 }
1781
1782 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1783 {
1784         if (version == 5) // In PROTOCOL_VERSION 13
1785         {
1786                 name = deSerializeString(is);
1787                 groups.clear();
1788                 u32 groups_size = readU16(is);
1789                 for(u32 i=0; i<groups_size; i++){
1790                         std::string name = deSerializeString(is);
1791                         int value = readS16(is);
1792                         groups[name] = value;
1793                 }
1794                 drawtype = (enum NodeDrawType)readU8(is);
1795
1796                 visual_scale = readF1000(is);
1797                 if (readU8(is) != 6)
1798                         throw SerializationError("unsupported tile count");
1799                 for (u32 i = 0; i < 6; i++)
1800                         tiledef[i].deSerialize(is, version, drawtype);
1801                 if (readU8(is) != CF_SPECIAL_COUNT)
1802                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1803                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1804                         tiledef_special[i].deSerialize(is, version, drawtype);
1805                 alpha = readU8(is);
1806                 post_effect_color.setAlpha(readU8(is));
1807                 post_effect_color.setRed(readU8(is));
1808                 post_effect_color.setGreen(readU8(is));
1809                 post_effect_color.setBlue(readU8(is));
1810                 param_type = (enum ContentParamType)readU8(is);
1811                 param_type_2 = (enum ContentParamType2)readU8(is);
1812                 is_ground_content = readU8(is);
1813                 light_propagates = readU8(is);
1814                 sunlight_propagates = readU8(is);
1815                 walkable = readU8(is);
1816                 pointable = readU8(is);
1817                 diggable = readU8(is);
1818                 climbable = readU8(is);
1819                 buildable_to = readU8(is);
1820                 deSerializeString(is); // legacy: used to be metadata_name
1821                 liquid_type = (enum LiquidType)readU8(is);
1822                 liquid_alternative_flowing = deSerializeString(is);
1823                 liquid_alternative_source = deSerializeString(is);
1824                 liquid_viscosity = readU8(is);
1825                 light_source = readU8(is);
1826                 light_source = MYMIN(light_source, LIGHT_MAX);
1827                 damage_per_second = readU32(is);
1828                 node_box.deSerialize(is);
1829                 selection_box.deSerialize(is);
1830                 legacy_facedir_simple = readU8(is);
1831                 legacy_wallmounted = readU8(is);
1832                 deSerializeSimpleSoundSpec(sound_footstep, is);
1833                 deSerializeSimpleSoundSpec(sound_dig, is);
1834                 deSerializeSimpleSoundSpec(sound_dug, is);
1835         } else if (version == 6) {
1836                 name = deSerializeString(is);
1837                 groups.clear();
1838                 u32 groups_size = readU16(is);
1839                 for (u32 i = 0; i < groups_size; i++) {
1840                         std::string name = deSerializeString(is);
1841                         int     value = readS16(is);
1842                         groups[name] = value;
1843                 }
1844                 drawtype = (enum NodeDrawType)readU8(is);
1845                 visual_scale = readF1000(is);
1846                 if (readU8(is) != 6)
1847                         throw SerializationError("unsupported tile count");
1848                 for (u32 i = 0; i < 6; i++)
1849                         tiledef[i].deSerialize(is, version, drawtype);
1850                 // CF_SPECIAL_COUNT in version 6 = 2
1851                 if (readU8(is) != 2)
1852                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1853                 for (u32 i = 0; i < 2; i++)
1854                         tiledef_special[i].deSerialize(is, version, drawtype);
1855                 alpha = readU8(is);
1856                 post_effect_color.setAlpha(readU8(is));
1857                 post_effect_color.setRed(readU8(is));
1858                 post_effect_color.setGreen(readU8(is));
1859                 post_effect_color.setBlue(readU8(is));
1860                 param_type = (enum ContentParamType)readU8(is);
1861                 param_type_2 = (enum ContentParamType2)readU8(is);
1862                 is_ground_content = readU8(is);
1863                 light_propagates = readU8(is);
1864                 sunlight_propagates = readU8(is);
1865                 walkable = readU8(is);
1866                 pointable = readU8(is);
1867                 diggable = readU8(is);
1868                 climbable = readU8(is);
1869                 buildable_to = readU8(is);
1870                 deSerializeString(is); // legacy: used to be metadata_name
1871                 liquid_type = (enum LiquidType)readU8(is);
1872                 liquid_alternative_flowing = deSerializeString(is);
1873                 liquid_alternative_source = deSerializeString(is);
1874                 liquid_viscosity = readU8(is);
1875                 liquid_renewable = readU8(is);
1876                 light_source = readU8(is);
1877                 damage_per_second = readU32(is);
1878                 node_box.deSerialize(is);
1879                 selection_box.deSerialize(is);
1880                 legacy_facedir_simple = readU8(is);
1881                 legacy_wallmounted = readU8(is);
1882                 deSerializeSimpleSoundSpec(sound_footstep, is);
1883                 deSerializeSimpleSoundSpec(sound_dig, is);
1884                 deSerializeSimpleSoundSpec(sound_dug, is);
1885                 rightclickable = readU8(is);
1886                 drowning = readU8(is);
1887                 leveled = readU8(is);
1888                 liquid_range = readU8(is);
1889         } else if (version == 7 || version == 8){
1890                 name = deSerializeString(is);
1891                 groups.clear();
1892                 u32 groups_size = readU16(is);
1893                 for (u32 i = 0; i < groups_size; i++) {
1894                         std::string name = deSerializeString(is);
1895                         int value = readS16(is);
1896                         groups[name] = value;
1897                 }
1898                 drawtype = (enum NodeDrawType) readU8(is);
1899
1900                 visual_scale = readF1000(is);
1901                 if (readU8(is) != 6)
1902                         throw SerializationError("unsupported tile count");
1903                 for (u32 i = 0; i < 6; i++)
1904                         tiledef[i].deSerialize(is, version, drawtype);
1905                 if (readU8(is) != CF_SPECIAL_COUNT)
1906                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1907                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1908                         tiledef_special[i].deSerialize(is, version, drawtype);
1909                 alpha = readU8(is);
1910                 post_effect_color.setAlpha(readU8(is));
1911                 post_effect_color.setRed(readU8(is));
1912                 post_effect_color.setGreen(readU8(is));
1913                 post_effect_color.setBlue(readU8(is));
1914                 param_type = (enum ContentParamType) readU8(is);
1915                 param_type_2 = (enum ContentParamType2) readU8(is);
1916                 is_ground_content = readU8(is);
1917                 light_propagates = readU8(is);
1918                 sunlight_propagates = readU8(is);
1919                 walkable = readU8(is);
1920                 pointable = readU8(is);
1921                 diggable = readU8(is);
1922                 climbable = readU8(is);
1923                 buildable_to = readU8(is);
1924                 deSerializeString(is); // legacy: used to be metadata_name
1925                 liquid_type = (enum LiquidType) readU8(is);
1926                 liquid_alternative_flowing = deSerializeString(is);
1927                 liquid_alternative_source = deSerializeString(is);
1928                 liquid_viscosity = readU8(is);
1929                 liquid_renewable = readU8(is);
1930                 light_source = readU8(is);
1931                 light_source = MYMIN(light_source, LIGHT_MAX);
1932                 damage_per_second = readU32(is);
1933                 node_box.deSerialize(is);
1934                 selection_box.deSerialize(is);
1935                 legacy_facedir_simple = readU8(is);
1936                 legacy_wallmounted = readU8(is);
1937                 deSerializeSimpleSoundSpec(sound_footstep, is);
1938                 deSerializeSimpleSoundSpec(sound_dig, is);
1939                 deSerializeSimpleSoundSpec(sound_dug, is);
1940                 rightclickable = readU8(is);
1941                 drowning = readU8(is);
1942                 leveled = readU8(is);
1943                 liquid_range = readU8(is);
1944                 waving = readU8(is);
1945                 try {
1946                         mesh = deSerializeString(is);
1947                         collision_box.deSerialize(is);
1948                         floodable = readU8(is);
1949                         u16 connects_to_size = readU16(is);
1950                         connects_to_ids.clear();
1951                         for (u16 i = 0; i < connects_to_size; i++)
1952                                 connects_to_ids.insert(readU16(is));
1953                         connect_sides = readU8(is);
1954                 } catch (SerializationError &e) {};
1955         }else{
1956                 throw SerializationError("unsupported ContentFeatures version");
1957         }
1958 }
1959
1960
1961 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1962 {
1963         return m_node_registration_complete;
1964 }
1965
1966
1967 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1968 {
1969         m_node_registration_complete = completed;
1970 }
1971
1972
1973 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1974 {
1975         nr->m_ndef = this;
1976         if (m_node_registration_complete)
1977                 nr->nodeResolveInternal();
1978         else
1979                 m_pending_resolve_callbacks.push_back(nr);
1980 }
1981
1982
1983 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1984 {
1985         size_t len = m_pending_resolve_callbacks.size();
1986         for (size_t i = 0; i != len; i++) {
1987                 if (nr != m_pending_resolve_callbacks[i])
1988                         continue;
1989
1990                 len--;
1991                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1992                 m_pending_resolve_callbacks.resize(len);
1993                 return true;
1994         }
1995
1996         return false;
1997 }
1998
1999
2000 void CNodeDefManager::runNodeResolveCallbacks()
2001 {
2002         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
2003                 NodeResolver *nr = m_pending_resolve_callbacks[i];
2004                 nr->nodeResolveInternal();
2005         }
2006
2007         m_pending_resolve_callbacks.clear();
2008 }
2009
2010
2011 void CNodeDefManager::resetNodeResolveState()
2012 {
2013         m_node_registration_complete = false;
2014         m_pending_resolve_callbacks.clear();
2015 }
2016
2017 void CNodeDefManager::mapNodeboxConnections()
2018 {
2019         for (u32 i = 0; i < m_content_features.size(); i++) {
2020                 ContentFeatures *f = &m_content_features[i];
2021                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
2022                         continue;
2023                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
2024                                 it != f->connects_to.end(); ++it) {
2025                         getIds(*it, f->connects_to_ids);
2026                 }
2027         }
2028 }
2029
2030 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
2031 {
2032         const ContentFeatures &f1 = get(from);
2033
2034         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
2035                 return false;
2036
2037         // lookup target in connected set
2038         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
2039                 return false;
2040
2041         const ContentFeatures &f2 = get(to);
2042
2043         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
2044                 // ignores actually looking if back connection exists
2045                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
2046
2047         // does to node declare usable faces?
2048         if (f2.connect_sides > 0) {
2049                 if ((f2.param_type_2 == CPT2_FACEDIR ||
2050                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
2051                                 && (connect_face >= 4)) {
2052                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2053                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2054                                 0, // 4 - back
2055                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2056                                 0, // 8 - right
2057                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
2058                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2059                                 0, // 16 - front
2060                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2061                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2062                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
2063                                 };
2064                         return (f2.connect_sides
2065                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
2066                 }
2067                 return (f2.connect_sides & connect_face);
2068         }
2069         // the target is just a regular node, so connect no matter back connection
2070         return true;
2071 }
2072
2073 ////
2074 //// NodeResolver
2075 ////
2076
2077 NodeResolver::NodeResolver()
2078 {
2079         m_ndef            = NULL;
2080         m_nodenames_idx   = 0;
2081         m_nnlistsizes_idx = 0;
2082         m_resolve_done    = false;
2083
2084         m_nodenames.reserve(16);
2085         m_nnlistsizes.reserve(4);
2086 }
2087
2088
2089 NodeResolver::~NodeResolver()
2090 {
2091         if (!m_resolve_done && m_ndef)
2092                 m_ndef->cancelNodeResolveCallback(this);
2093 }
2094
2095
2096 void NodeResolver::nodeResolveInternal()
2097 {
2098         m_nodenames_idx   = 0;
2099         m_nnlistsizes_idx = 0;
2100
2101         resolveNodeNames();
2102         m_resolve_done = true;
2103
2104         m_nodenames.clear();
2105         m_nnlistsizes.clear();
2106 }
2107
2108
2109 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
2110         const std::string &node_alt, content_t c_fallback)
2111 {
2112         if (m_nodenames_idx == m_nodenames.size()) {
2113                 *result_out = c_fallback;
2114                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
2115                 return false;
2116         }
2117
2118         content_t c;
2119         std::string name = m_nodenames[m_nodenames_idx++];
2120
2121         bool success = m_ndef->getId(name, c);
2122         if (!success && node_alt != "") {
2123                 name = node_alt;
2124                 success = m_ndef->getId(name, c);
2125         }
2126
2127         if (!success) {
2128                 errorstream << "NodeResolver: failed to resolve node name '" << name
2129                         << "'." << std::endl;
2130                 c = c_fallback;
2131         }
2132
2133         *result_out = c;
2134         return success;
2135 }
2136
2137
2138 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
2139         bool all_required, content_t c_fallback)
2140 {
2141         bool success = true;
2142
2143         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
2144                 errorstream << "NodeResolver: no more node lists" << std::endl;
2145                 return false;
2146         }
2147
2148         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
2149
2150         while (length--) {
2151                 if (m_nodenames_idx == m_nodenames.size()) {
2152                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
2153                         return false;
2154                 }
2155
2156                 content_t c;
2157                 std::string &name = m_nodenames[m_nodenames_idx++];
2158
2159                 if (name.substr(0,6) != "group:") {
2160                         if (m_ndef->getId(name, c)) {
2161                                 result_out->push_back(c);
2162                         } else if (all_required) {
2163                                 errorstream << "NodeResolver: failed to resolve node name '"
2164                                         << name << "'." << std::endl;
2165                                 result_out->push_back(c_fallback);
2166                                 success = false;
2167                         }
2168                 } else {
2169                         std::set<content_t> cids;
2170                         std::set<content_t>::iterator it;
2171                         m_ndef->getIds(name, cids);
2172                         for (it = cids.begin(); it != cids.end(); ++it)
2173                                 result_out->push_back(*it);
2174                 }
2175         }
2176
2177         return success;
2178 }