Speed up emerge thread by using unordered map in a few places. Looking at 25% speedup...
[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         UNORDERED_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         UNORDERED_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         UNORDERED_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         UNORDERED_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                 UNORDERED_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 (UNORDERED_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                         continue; // Ignore unknown node
1149
1150                 ContentFeatures &nodedef = m_content_features[id];
1151
1152                 if (splitted[1] == "top")
1153                         nodedef.tiledef[0].name = splitted[2];
1154                 else if (splitted[1] == "bottom")
1155                         nodedef.tiledef[1].name = splitted[2];
1156                 else if (splitted[1] == "right")
1157                         nodedef.tiledef[2].name = splitted[2];
1158                 else if (splitted[1] == "left")
1159                         nodedef.tiledef[3].name = splitted[2];
1160                 else if (splitted[1] == "back")
1161                         nodedef.tiledef[4].name = splitted[2];
1162                 else if (splitted[1] == "front")
1163                         nodedef.tiledef[5].name = splitted[2];
1164                 else if (splitted[1] == "all" || splitted[1] == "*")
1165                         for (int i = 0; i < 6; i++)
1166                                 nodedef.tiledef[i].name = splitted[2];
1167                 else if (splitted[1] == "sides")
1168                         for (int i = 2; i < 6; i++)
1169                                 nodedef.tiledef[i].name = splitted[2];
1170                 else {
1171                         errorstream << override_filepath
1172                                 << ":" << line_c << " Could not apply texture override \""
1173                                 << line << "\": Unknown node side \""
1174                                 << splitted[1] << "\"" << std::endl;
1175                         continue;
1176                 }
1177         }
1178 }
1179
1180 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1181         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1182         void *progress_callback_args)
1183 {
1184 #ifndef SERVER
1185         infostream << "CNodeDefManager::updateTextures(): Updating "
1186                 "textures in node definitions" << std::endl;
1187         ITextureSource *tsrc = gamedef->tsrc();
1188         IShaderSource *shdsrc = gamedef->getShaderSource();
1189         scene::ISceneManager* smgr = gamedef->getSceneManager();
1190         scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1191         TextureSettings tsettings;
1192         tsettings.readSettings();
1193
1194         u32 size = m_content_features.size();
1195
1196         for (u32 i = 0; i < size; i++) {
1197                 m_content_features[i].updateTextures(tsrc, shdsrc, smgr, meshmanip, gamedef, tsettings);
1198                 progress_callback(progress_callback_args, i, size);
1199         }
1200 #endif
1201 }
1202
1203 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1204 {
1205         writeU8(os, 1); // version
1206         u16 count = 0;
1207         std::ostringstream os2(std::ios::binary);
1208         for (u32 i = 0; i < m_content_features.size(); i++) {
1209                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1210                                 || i == CONTENT_UNKNOWN)
1211                         continue;
1212                 const ContentFeatures *f = &m_content_features[i];
1213                 if (f->name == "")
1214                         continue;
1215                 writeU16(os2, i);
1216                 // Wrap it in a string to allow different lengths without
1217                 // strict version incompatibilities
1218                 std::ostringstream wrapper_os(std::ios::binary);
1219                 f->serialize(wrapper_os, protocol_version);
1220                 os2<<serializeString(wrapper_os.str());
1221
1222                 // must not overflow
1223                 u16 next = count + 1;
1224                 FATAL_ERROR_IF(next < count, "Overflow");
1225                 count++;
1226         }
1227         writeU16(os, count);
1228         os << serializeLongString(os2.str());
1229 }
1230
1231
1232 void CNodeDefManager::deSerialize(std::istream &is)
1233 {
1234         clear();
1235         int version = readU8(is);
1236         if (version != 1)
1237                 throw SerializationError("unsupported NodeDefinitionManager version");
1238         u16 count = readU16(is);
1239         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1240         ContentFeatures f;
1241         for (u16 n = 0; n < count; n++) {
1242                 u16 i = readU16(is2);
1243
1244                 // Read it from the string wrapper
1245                 std::string wrapper = deSerializeString(is2);
1246                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1247                 f.deSerialize(wrapper_is);
1248
1249                 // Check error conditions
1250                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1251                         warningstream << "NodeDefManager::deSerialize(): "
1252                                 "not changing builtin node " << i << std::endl;
1253                         continue;
1254                 }
1255                 if (f.name == "") {
1256                         warningstream << "NodeDefManager::deSerialize(): "
1257                                 "received empty name" << std::endl;
1258                         continue;
1259                 }
1260
1261                 // Ignore aliases
1262                 u16 existing_id;
1263                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1264                         warningstream << "NodeDefManager::deSerialize(): "
1265                                 "already defined with different ID: " << f.name << std::endl;
1266                         continue;
1267                 }
1268
1269                 // All is ok, add node definition with the requested ID
1270                 if (i >= m_content_features.size())
1271                         m_content_features.resize((u32)(i) + 1);
1272                 m_content_features[i] = f;
1273                 addNameIdMapping(i, f.name);
1274                 verbosestream << "deserialized " << f.name << std::endl;
1275         }
1276 }
1277
1278
1279 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1280 {
1281         m_name_id_mapping.set(i, name);
1282         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1283 }
1284
1285
1286 IWritableNodeDefManager *createNodeDefManager()
1287 {
1288         return new CNodeDefManager();
1289 }
1290
1291
1292 //// Serialization of old ContentFeatures formats
1293 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1294 {
1295         if (protocol_version == 13)
1296         {
1297                 writeU8(os, 5); // version
1298                 os<<serializeString(name);
1299                 writeU16(os, groups.size());
1300                 for (ItemGroupList::const_iterator
1301                                 i = groups.begin(); i != groups.end(); ++i) {
1302                         os<<serializeString(i->first);
1303                         writeS16(os, i->second);
1304                 }
1305                 writeU8(os, drawtype);
1306                 writeF1000(os, visual_scale);
1307                 writeU8(os, 6);
1308                 for (u32 i = 0; i < 6; i++)
1309                         tiledef[i].serialize(os, protocol_version);
1310                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1311                 writeU8(os, 2);
1312                 for (u32 i = 0; i < 2; i++)
1313                         tiledef_special[i].serialize(os, protocol_version);
1314                 writeU8(os, alpha);
1315                 writeU8(os, post_effect_color.getAlpha());
1316                 writeU8(os, post_effect_color.getRed());
1317                 writeU8(os, post_effect_color.getGreen());
1318                 writeU8(os, post_effect_color.getBlue());
1319                 writeU8(os, param_type);
1320                 writeU8(os, param_type_2);
1321                 writeU8(os, is_ground_content);
1322                 writeU8(os, light_propagates);
1323                 writeU8(os, sunlight_propagates);
1324                 writeU8(os, walkable);
1325                 writeU8(os, pointable);
1326                 writeU8(os, diggable);
1327                 writeU8(os, climbable);
1328                 writeU8(os, buildable_to);
1329                 os<<serializeString(""); // legacy: used to be metadata_name
1330                 writeU8(os, liquid_type);
1331                 os<<serializeString(liquid_alternative_flowing);
1332                 os<<serializeString(liquid_alternative_source);
1333                 writeU8(os, liquid_viscosity);
1334                 writeU8(os, light_source);
1335                 writeU32(os, damage_per_second);
1336                 node_box.serialize(os, protocol_version);
1337                 selection_box.serialize(os, protocol_version);
1338                 writeU8(os, legacy_facedir_simple);
1339                 writeU8(os, legacy_wallmounted);
1340                 serializeSimpleSoundSpec(sound_footstep, os);
1341                 serializeSimpleSoundSpec(sound_dig, os);
1342                 serializeSimpleSoundSpec(sound_dug, os);
1343         }
1344         else if (protocol_version > 13 && protocol_version < 24) {
1345                 writeU8(os, 6); // version
1346                 os<<serializeString(name);
1347                 writeU16(os, groups.size());
1348                 for (ItemGroupList::const_iterator
1349                         i = groups.begin(); i != groups.end(); ++i) {
1350                                 os<<serializeString(i->first);
1351                                 writeS16(os, i->second);
1352                 }
1353                 writeU8(os, drawtype);
1354                 writeF1000(os, visual_scale);
1355                 writeU8(os, 6);
1356                 for (u32 i = 0; i < 6; i++)
1357                         tiledef[i].serialize(os, protocol_version);
1358                 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1359                 writeU8(os, 2);
1360                 for (u32 i = 0; i < 2; i++)
1361                         tiledef_special[i].serialize(os, protocol_version);
1362                 writeU8(os, alpha);
1363                 writeU8(os, post_effect_color.getAlpha());
1364                 writeU8(os, post_effect_color.getRed());
1365                 writeU8(os, post_effect_color.getGreen());
1366                 writeU8(os, post_effect_color.getBlue());
1367                 writeU8(os, param_type);
1368                 writeU8(os, param_type_2);
1369                 writeU8(os, is_ground_content);
1370                 writeU8(os, light_propagates);
1371                 writeU8(os, sunlight_propagates);
1372                 writeU8(os, walkable);
1373                 writeU8(os, pointable);
1374                 writeU8(os, diggable);
1375                 writeU8(os, climbable);
1376                 writeU8(os, buildable_to);
1377                 os<<serializeString(""); // legacy: used to be metadata_name
1378                 writeU8(os, liquid_type);
1379                 os<<serializeString(liquid_alternative_flowing);
1380                 os<<serializeString(liquid_alternative_source);
1381                 writeU8(os, liquid_viscosity);
1382                 writeU8(os, liquid_renewable);
1383                 writeU8(os, light_source);
1384                 writeU32(os, damage_per_second);
1385                 node_box.serialize(os, protocol_version);
1386                 selection_box.serialize(os, protocol_version);
1387                 writeU8(os, legacy_facedir_simple);
1388                 writeU8(os, legacy_wallmounted);
1389                 serializeSimpleSoundSpec(sound_footstep, os);
1390                 serializeSimpleSoundSpec(sound_dig, os);
1391                 serializeSimpleSoundSpec(sound_dug, os);
1392                 writeU8(os, rightclickable);
1393                 writeU8(os, drowning);
1394                 writeU8(os, leveled);
1395                 writeU8(os, liquid_range);
1396         } else
1397                 throw SerializationError("ContentFeatures::serialize(): "
1398                         "Unsupported version requested");
1399 }
1400
1401 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1402 {
1403         if (version == 5) // In PROTOCOL_VERSION 13
1404         {
1405                 name = deSerializeString(is);
1406                 groups.clear();
1407                 u32 groups_size = readU16(is);
1408                 for(u32 i=0; i<groups_size; i++){
1409                         std::string name = deSerializeString(is);
1410                         int value = readS16(is);
1411                         groups[name] = value;
1412                 }
1413                 drawtype = (enum NodeDrawType)readU8(is);
1414
1415                 visual_scale = readF1000(is);
1416                 if (readU8(is) != 6)
1417                         throw SerializationError("unsupported tile count");
1418                 for (u32 i = 0; i < 6; i++)
1419                         tiledef[i].deSerialize(is, version, drawtype);
1420                 if (readU8(is) != CF_SPECIAL_COUNT)
1421                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1422                 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1423                         tiledef_special[i].deSerialize(is, version, drawtype);
1424                 alpha = readU8(is);
1425                 post_effect_color.setAlpha(readU8(is));
1426                 post_effect_color.setRed(readU8(is));
1427                 post_effect_color.setGreen(readU8(is));
1428                 post_effect_color.setBlue(readU8(is));
1429                 param_type = (enum ContentParamType)readU8(is);
1430                 param_type_2 = (enum ContentParamType2)readU8(is);
1431                 is_ground_content = readU8(is);
1432                 light_propagates = readU8(is);
1433                 sunlight_propagates = readU8(is);
1434                 walkable = readU8(is);
1435                 pointable = readU8(is);
1436                 diggable = readU8(is);
1437                 climbable = readU8(is);
1438                 buildable_to = readU8(is);
1439                 deSerializeString(is); // legacy: used to be metadata_name
1440                 liquid_type = (enum LiquidType)readU8(is);
1441                 liquid_alternative_flowing = deSerializeString(is);
1442                 liquid_alternative_source = deSerializeString(is);
1443                 liquid_viscosity = readU8(is);
1444                 light_source = readU8(is);
1445                 damage_per_second = readU32(is);
1446                 node_box.deSerialize(is);
1447                 selection_box.deSerialize(is);
1448                 legacy_facedir_simple = readU8(is);
1449                 legacy_wallmounted = readU8(is);
1450                 deSerializeSimpleSoundSpec(sound_footstep, is);
1451                 deSerializeSimpleSoundSpec(sound_dig, is);
1452                 deSerializeSimpleSoundSpec(sound_dug, is);
1453         } else if (version == 6) {
1454                 name = deSerializeString(is);
1455                 groups.clear();
1456                 u32 groups_size = readU16(is);
1457                 for (u32 i = 0; i < groups_size; i++) {
1458                         std::string name = deSerializeString(is);
1459                         int     value = readS16(is);
1460                         groups[name] = value;
1461                 }
1462                 drawtype = (enum NodeDrawType)readU8(is);
1463                 visual_scale = readF1000(is);
1464                 if (readU8(is) != 6)
1465                         throw SerializationError("unsupported tile count");
1466                 for (u32 i = 0; i < 6; i++)
1467                         tiledef[i].deSerialize(is, version, drawtype);
1468                 // CF_SPECIAL_COUNT in version 6 = 2
1469                 if (readU8(is) != 2)
1470                         throw SerializationError("unsupported CF_SPECIAL_COUNT");
1471                 for (u32 i = 0; i < 2; i++)
1472                         tiledef_special[i].deSerialize(is, version, drawtype);
1473                 alpha = readU8(is);
1474                 post_effect_color.setAlpha(readU8(is));
1475                 post_effect_color.setRed(readU8(is));
1476                 post_effect_color.setGreen(readU8(is));
1477                 post_effect_color.setBlue(readU8(is));
1478                 param_type = (enum ContentParamType)readU8(is);
1479                 param_type_2 = (enum ContentParamType2)readU8(is);
1480                 is_ground_content = readU8(is);
1481                 light_propagates = readU8(is);
1482                 sunlight_propagates = readU8(is);
1483                 walkable = readU8(is);
1484                 pointable = readU8(is);
1485                 diggable = readU8(is);
1486                 climbable = readU8(is);
1487                 buildable_to = readU8(is);
1488                 deSerializeString(is); // legacy: used to be metadata_name
1489                 liquid_type = (enum LiquidType)readU8(is);
1490                 liquid_alternative_flowing = deSerializeString(is);
1491                 liquid_alternative_source = deSerializeString(is);
1492                 liquid_viscosity = readU8(is);
1493                 liquid_renewable = readU8(is);
1494                 light_source = readU8(is);
1495                 damage_per_second = readU32(is);
1496                 node_box.deSerialize(is);
1497                 selection_box.deSerialize(is);
1498                 legacy_facedir_simple = readU8(is);
1499                 legacy_wallmounted = readU8(is);
1500                 deSerializeSimpleSoundSpec(sound_footstep, is);
1501                 deSerializeSimpleSoundSpec(sound_dig, is);
1502                 deSerializeSimpleSoundSpec(sound_dug, is);
1503                 rightclickable = readU8(is);
1504                 drowning = readU8(is);
1505                 leveled = readU8(is);
1506                 liquid_range = readU8(is);
1507         } else {
1508                 throw SerializationError("unsupported ContentFeatures version");
1509         }
1510 }
1511
1512
1513 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1514 {
1515         return m_node_registration_complete;
1516 }
1517
1518
1519 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1520 {
1521         m_node_registration_complete = completed;
1522 }
1523
1524
1525 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1526 {
1527         nr->m_ndef = this;
1528         if (m_node_registration_complete)
1529                 nr->nodeResolveInternal();
1530         else
1531                 m_pending_resolve_callbacks.push_back(nr);
1532 }
1533
1534
1535 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1536 {
1537         size_t len = m_pending_resolve_callbacks.size();
1538         for (size_t i = 0; i != len; i++) {
1539                 if (nr != m_pending_resolve_callbacks[i])
1540                         continue;
1541
1542                 len--;
1543                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1544                 m_pending_resolve_callbacks.resize(len);
1545                 return true;
1546         }
1547
1548         return false;
1549 }
1550
1551
1552 void CNodeDefManager::runNodeResolveCallbacks()
1553 {
1554         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1555                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1556                 nr->nodeResolveInternal();
1557         }
1558
1559         m_pending_resolve_callbacks.clear();
1560 }
1561
1562
1563 void CNodeDefManager::resetNodeResolveState()
1564 {
1565         m_node_registration_complete = false;
1566         m_pending_resolve_callbacks.clear();
1567 }
1568
1569 void CNodeDefManager::mapNodeboxConnections()
1570 {
1571         for (u32 i = 0; i < m_content_features.size(); i++) {
1572                 ContentFeatures *f = &m_content_features[i];
1573                 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1574                         continue;
1575                 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1576                                 it != f->connects_to.end(); ++it) {
1577                         getIds(*it, f->connects_to_ids);
1578                 }
1579         }
1580 }
1581
1582 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1583 {
1584         const ContentFeatures &f1 = get(from);
1585
1586         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1587                 return false;
1588
1589         // lookup target in connected set
1590         if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1591                 return false;
1592
1593         const ContentFeatures &f2 = get(to);
1594
1595         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1596                 // ignores actually looking if back connection exists
1597                 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1598
1599         // does to node declare usable faces?
1600         if (f2.connect_sides > 0) {
1601                 if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
1602                         static const u8 rot[33 * 4] = {
1603                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1604                                 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
1605                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
1606                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1607                                 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
1608                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1609                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1610                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1611                                 32, 16, 8, 4 // 32 - left
1612                         };
1613                         return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
1614                 }
1615                 return (f2.connect_sides & connect_face);
1616         }
1617         // the target is just a regular node, so connect no matter back connection
1618         return true;
1619 }
1620
1621 ////
1622 //// NodeResolver
1623 ////
1624
1625 NodeResolver::NodeResolver()
1626 {
1627         m_ndef            = NULL;
1628         m_nodenames_idx   = 0;
1629         m_nnlistsizes_idx = 0;
1630         m_resolve_done    = false;
1631
1632         m_nodenames.reserve(16);
1633         m_nnlistsizes.reserve(4);
1634 }
1635
1636
1637 NodeResolver::~NodeResolver()
1638 {
1639         if (!m_resolve_done && m_ndef)
1640                 m_ndef->cancelNodeResolveCallback(this);
1641 }
1642
1643
1644 void NodeResolver::nodeResolveInternal()
1645 {
1646         m_nodenames_idx   = 0;
1647         m_nnlistsizes_idx = 0;
1648
1649         resolveNodeNames();
1650         m_resolve_done = true;
1651
1652         m_nodenames.clear();
1653         m_nnlistsizes.clear();
1654 }
1655
1656
1657 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1658         const std::string &node_alt, content_t c_fallback)
1659 {
1660         if (m_nodenames_idx == m_nodenames.size()) {
1661                 *result_out = c_fallback;
1662                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1663                 return false;
1664         }
1665
1666         content_t c;
1667         std::string name = m_nodenames[m_nodenames_idx++];
1668
1669         bool success = m_ndef->getId(name, c);
1670         if (!success && node_alt != "") {
1671                 name = node_alt;
1672                 success = m_ndef->getId(name, c);
1673         }
1674
1675         if (!success) {
1676                 errorstream << "NodeResolver: failed to resolve node name '" << name
1677                         << "'." << std::endl;
1678                 c = c_fallback;
1679         }
1680
1681         *result_out = c;
1682         return success;
1683 }
1684
1685
1686 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1687         bool all_required, content_t c_fallback)
1688 {
1689         bool success = true;
1690
1691         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1692                 errorstream << "NodeResolver: no more node lists" << std::endl;
1693                 return false;
1694         }
1695
1696         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1697
1698         while (length--) {
1699                 if (m_nodenames_idx == m_nodenames.size()) {
1700                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1701                         return false;
1702                 }
1703
1704                 content_t c;
1705                 std::string &name = m_nodenames[m_nodenames_idx++];
1706
1707                 if (name.substr(0,6) != "group:") {
1708                         if (m_ndef->getId(name, c)) {
1709                                 result_out->push_back(c);
1710                         } else if (all_required) {
1711                                 errorstream << "NodeResolver: failed to resolve node name '"
1712                                         << name << "'." << std::endl;
1713                                 result_out->push_back(c_fallback);
1714                                 success = false;
1715                         }
1716                 } else {
1717                         std::set<content_t> cids;
1718                         std::set<content_t>::iterator it;
1719                         m_ndef->getIds(name, cids);
1720                         for (it = cids.begin(); it != cids.end(); ++it)
1721                                 result_out->push_back(*it);
1722                 }
1723         }
1724
1725         return success;
1726 }