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