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