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