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