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