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