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