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