]> git.lizzy.rs Git - minetest.git/blob - src/nodedef.cpp
Conf.example generation: Remove quotation marks from noise flags (#7844)
[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 "mesh.h"
25 #include "shader.h"
26 #include "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         int version = 5;
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                         writeV3F1000(os, nodebox.MinEdge);
88                         writeV3F1000(os, nodebox.MaxEdge);
89                 }
90                 break;
91         case NODEBOX_WALLMOUNTED:
92                 writeU8(os, type);
93
94                 writeV3F1000(os, wall_top.MinEdge);
95                 writeV3F1000(os, wall_top.MaxEdge);
96                 writeV3F1000(os, wall_bottom.MinEdge);
97                 writeV3F1000(os, wall_bottom.MaxEdge);
98                 writeV3F1000(os, wall_side.MinEdge);
99                 writeV3F1000(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                         writeV3F1000(os, i.MinEdge); \
108                         writeV3F1000(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 < 4)
137                 throw SerializationError("unsupported NodeBox version");
138
139         reset();
140
141         type = (enum NodeBoxType)readU8(is);
142
143         if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
144         {
145                 u16 fixed_count = readU16(is);
146                 while(fixed_count--)
147                 {
148                         aabb3f box;
149                         box.MinEdge = readV3F1000(is);
150                         box.MaxEdge = readV3F1000(is);
151                         fixed.push_back(box);
152                 }
153         }
154         else if(type == NODEBOX_WALLMOUNTED)
155         {
156                 wall_top.MinEdge = readV3F1000(is);
157                 wall_top.MaxEdge = readV3F1000(is);
158                 wall_bottom.MinEdge = readV3F1000(is);
159                 wall_bottom.MaxEdge = readV3F1000(is);
160                 wall_side.MinEdge = readV3F1000(is);
161                 wall_side.MaxEdge = readV3F1000(is);
162         }
163         else if (type == NODEBOX_CONNECTED)
164         {
165 #define READBOXES(box) { \
166                 count = readU16(is); \
167                 (box).reserve(count); \
168                 while (count--) { \
169                         v3f min = readV3F1000(is); \
170                         v3f max = readV3F1000(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                 if (version >= 5) {
183                         READBOXES(disconnected_top);
184                         READBOXES(disconnected_bottom);
185                         READBOXES(disconnected_front);
186                         READBOXES(disconnected_left);
187                         READBOXES(disconnected_back);
188                         READBOXES(disconnected_right);
189                         READBOXES(disconnected);
190                         READBOXES(disconnected_sides);
191                 }
192         }
193 }
194
195 /*
196         TileDef
197 */
198
199 #define TILE_FLAG_BACKFACE_CULLING      (1 << 0)
200 #define TILE_FLAG_TILEABLE_HORIZONTAL   (1 << 1)
201 #define TILE_FLAG_TILEABLE_VERTICAL     (1 << 2)
202 #define TILE_FLAG_HAS_COLOR     (1 << 3)
203 #define TILE_FLAG_HAS_SCALE     (1 << 4)
204 #define TILE_FLAG_HAS_ALIGN_STYLE       (1 << 5)
205
206 void TileDef::serialize(std::ostream &os, u16 protocol_version) const
207 {
208         // protocol_version >= 36
209         u8 version = 6;
210         writeU8(os, version);
211
212         os << serializeString(name);
213         animation.serialize(os, version);
214         bool has_scale = scale > 0;
215         u16 flags = 0;
216         if (backface_culling)
217                 flags |= TILE_FLAG_BACKFACE_CULLING;
218         if (tileable_horizontal)
219                 flags |= TILE_FLAG_TILEABLE_HORIZONTAL;
220         if (tileable_vertical)
221                 flags |= TILE_FLAG_TILEABLE_VERTICAL;
222         if (has_color)
223                 flags |= TILE_FLAG_HAS_COLOR;
224         if (has_scale)
225                 flags |= TILE_FLAG_HAS_SCALE;
226         if (align_style != ALIGN_STYLE_NODE)
227                 flags |= TILE_FLAG_HAS_ALIGN_STYLE;
228         writeU16(os, flags);
229         if (has_color) {
230                 writeU8(os, color.getRed());
231                 writeU8(os, color.getGreen());
232                 writeU8(os, color.getBlue());
233         }
234         if (has_scale)
235                 writeU8(os, scale);
236         if (align_style != ALIGN_STYLE_NODE)
237                 writeU8(os, align_style);
238 }
239
240 void TileDef::deSerialize(std::istream &is, u8 contentfeatures_version,
241         NodeDrawType drawtype)
242 {
243         int version = readU8(is);
244         if (version < 6)
245                 throw SerializationError("unsupported TileDef version");
246         name = deSerializeString(is);
247         animation.deSerialize(is, version);
248         u16 flags = readU16(is);
249         backface_culling = flags & TILE_FLAG_BACKFACE_CULLING;
250         tileable_horizontal = flags & TILE_FLAG_TILEABLE_HORIZONTAL;
251         tileable_vertical = flags & TILE_FLAG_TILEABLE_VERTICAL;
252         has_color = flags & TILE_FLAG_HAS_COLOR;
253         bool has_scale = flags & TILE_FLAG_HAS_SCALE;
254         bool has_align_style = flags & TILE_FLAG_HAS_ALIGN_STYLE;
255         if (has_color) {
256                 color.setRed(readU8(is));
257                 color.setGreen(readU8(is));
258                 color.setBlue(readU8(is));
259         }
260         scale = has_scale ? readU8(is) : 0;
261         if (has_align_style)
262                 align_style = static_cast<AlignStyle>(readU8(is));
263         else
264                 align_style = ALIGN_STYLE_NODE;
265 }
266
267
268 /*
269         SimpleSoundSpec serialization
270 */
271
272 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
273                 std::ostream &os, u8 version)
274 {
275         os<<serializeString(ss.name);
276         writeF1000(os, ss.gain);
277         writeF1000(os, ss.pitch);
278 }
279 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss,
280                 std::istream &is, u8 version)
281 {
282         ss.name = deSerializeString(is);
283         ss.gain = readF1000(is);
284         ss.pitch = readF1000(is);
285 }
286
287 void TextureSettings::readSettings()
288 {
289         connected_glass                = g_settings->getBool("connected_glass");
290         opaque_water                   = g_settings->getBool("opaque_water");
291         bool enable_shaders            = g_settings->getBool("enable_shaders");
292         bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
293         bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
294         bool smooth_lighting           = g_settings->getBool("smooth_lighting");
295         enable_mesh_cache              = g_settings->getBool("enable_mesh_cache");
296         enable_minimap                 = g_settings->getBool("enable_minimap");
297         node_texture_size              = g_settings->getU16("texture_min_size");
298         std::string leaves_style_str   = g_settings->get("leaves_style");
299         std::string world_aligned_mode_str = g_settings->get("world_aligned_mode");
300         std::string autoscale_mode_str = g_settings->get("autoscale_mode");
301
302         // Mesh cache is not supported in combination with smooth lighting
303         if (smooth_lighting)
304                 enable_mesh_cache = false;
305
306         use_normal_texture = enable_shaders &&
307                 (enable_bumpmapping || enable_parallax_occlusion);
308         if (leaves_style_str == "fancy") {
309                 leaves_style = LEAVES_FANCY;
310         } else if (leaves_style_str == "simple") {
311                 leaves_style = LEAVES_SIMPLE;
312         } else {
313                 leaves_style = LEAVES_OPAQUE;
314         }
315
316         if (world_aligned_mode_str == "enable")
317                 world_aligned_mode = WORLDALIGN_ENABLE;
318         else if (world_aligned_mode_str == "force_solid")
319                 world_aligned_mode = WORLDALIGN_FORCE;
320         else if (world_aligned_mode_str == "force_nodebox")
321                 world_aligned_mode = WORLDALIGN_FORCE_NODEBOX;
322         else
323                 world_aligned_mode = WORLDALIGN_DISABLE;
324
325         if (autoscale_mode_str == "enable")
326                 autoscale_mode = AUTOSCALE_ENABLE;
327         else if (autoscale_mode_str == "force")
328                 autoscale_mode = AUTOSCALE_FORCE;
329         else
330                 autoscale_mode = AUTOSCALE_DISABLE;
331 }
332
333 /*
334         ContentFeatures
335 */
336
337 ContentFeatures::ContentFeatures()
338 {
339         reset();
340 }
341
342 void ContentFeatures::reset()
343 {
344         /*
345                 Cached stuff
346         */
347 #ifndef SERVER
348         solidness = 2;
349         visual_solidness = 0;
350         backface_culling = true;
351
352 #endif
353         has_on_construct = false;
354         has_on_destruct = false;
355         has_after_destruct = false;
356         /*
357                 Actual data
358
359                 NOTE: Most of this is always overridden by the default values given
360                       in builtin.lua
361         */
362         name = "";
363         groups.clear();
364         // Unknown nodes can be dug
365         groups["dig_immediate"] = 2;
366         drawtype = NDT_NORMAL;
367         mesh = "";
368 #ifndef SERVER
369         for (auto &i : mesh_ptr)
370                 i = NULL;
371         minimap_color = video::SColor(0, 0, 0, 0);
372 #endif
373         visual_scale = 1.0;
374         for (auto &i : tiledef)
375                 i = TileDef();
376         for (auto &j : tiledef_special)
377                 j = TileDef();
378         alpha = 255;
379         post_effect_color = video::SColor(0, 0, 0, 0);
380         param_type = CPT_NONE;
381         param_type_2 = CPT2_NONE;
382         is_ground_content = false;
383         light_propagates = false;
384         sunlight_propagates = false;
385         walkable = true;
386         pointable = true;
387         diggable = true;
388         climbable = false;
389         buildable_to = false;
390         floodable = false;
391         rightclickable = true;
392         leveled = 0;
393         liquid_type = LIQUID_NONE;
394         liquid_alternative_flowing = "";
395         liquid_alternative_source = "";
396         liquid_viscosity = 0;
397         liquid_renewable = true;
398         liquid_range = LIQUID_LEVEL_MAX+1;
399         drowning = 0;
400         light_source = 0;
401         damage_per_second = 0;
402         node_box = NodeBox();
403         selection_box = NodeBox();
404         collision_box = NodeBox();
405         waving = 0;
406         legacy_facedir_simple = false;
407         legacy_wallmounted = false;
408         sound_footstep = SimpleSoundSpec();
409         sound_dig = SimpleSoundSpec("__group");
410         sound_dug = SimpleSoundSpec();
411         connects_to.clear();
412         connects_to_ids.clear();
413         connect_sides = 0;
414         color = video::SColor(0xFFFFFFFF);
415         palette_name = "";
416         palette = NULL;
417         node_dig_prediction = "air";
418 }
419
420 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
421 {
422         // protocol_version >= 36
423         u8 version = 12;
424         writeU8(os, version);
425
426         // general
427         os << serializeString(name);
428         writeU16(os, groups.size());
429         for (const auto &group : groups) {
430                 os << serializeString(group.first);
431                 writeS16(os, group.second);
432         }
433         writeU8(os, param_type);
434         writeU8(os, param_type_2);
435
436         // visual
437         writeU8(os, drawtype);
438         os << serializeString(mesh);
439         writeF1000(os, visual_scale);
440         writeU8(os, 6);
441         for (const TileDef &td : tiledef)
442                 td.serialize(os, protocol_version);
443         for (const TileDef &td : tiledef_overlay)
444                 td.serialize(os, protocol_version);
445         writeU8(os, CF_SPECIAL_COUNT);
446         for (const TileDef &td : tiledef_special) {
447                 td.serialize(os, protocol_version);
448         }
449         writeU8(os, alpha);
450         writeU8(os, color.getRed());
451         writeU8(os, color.getGreen());
452         writeU8(os, color.getBlue());
453         os << serializeString(palette_name);
454         writeU8(os, waving);
455         writeU8(os, connect_sides);
456         writeU16(os, connects_to_ids.size());
457         for (u16 connects_to_id : connects_to_ids)
458                 writeU16(os, connects_to_id);
459         writeU8(os, post_effect_color.getAlpha());
460         writeU8(os, post_effect_color.getRed());
461         writeU8(os, post_effect_color.getGreen());
462         writeU8(os, post_effect_color.getBlue());
463         writeU8(os, leveled);
464
465         // lighting
466         writeU8(os, light_propagates);
467         writeU8(os, sunlight_propagates);
468         writeU8(os, light_source);
469
470         // map generation
471         writeU8(os, is_ground_content);
472
473         // interaction
474         writeU8(os, walkable);
475         writeU8(os, pointable);
476         writeU8(os, diggable);
477         writeU8(os, climbable);
478         writeU8(os, buildable_to);
479         writeU8(os, rightclickable);
480         writeU32(os, damage_per_second);
481
482         // liquid
483         writeU8(os, liquid_type);
484         os << serializeString(liquid_alternative_flowing);
485         os << serializeString(liquid_alternative_source);
486         writeU8(os, liquid_viscosity);
487         writeU8(os, liquid_renewable);
488         writeU8(os, liquid_range);
489         writeU8(os, drowning);
490         writeU8(os, floodable);
491
492         // node boxes
493         node_box.serialize(os, protocol_version);
494         selection_box.serialize(os, protocol_version);
495         collision_box.serialize(os, protocol_version);
496
497         // sound
498         serializeSimpleSoundSpec(sound_footstep, os, version);
499         serializeSimpleSoundSpec(sound_dig, os, version);
500         serializeSimpleSoundSpec(sound_dug, os, version);
501
502         // legacy
503         writeU8(os, legacy_facedir_simple);
504         writeU8(os, legacy_wallmounted);
505
506         os << serializeString(node_dig_prediction);
507 }
508
509 void ContentFeatures::correctAlpha(TileDef *tiles, int length)
510 {
511         // alpha == 0 means that the node is using texture alpha
512         if (alpha == 0 || alpha == 255)
513                 return;
514
515         for (int i = 0; i < length; i++) {
516                 if (tiles[i].name.empty())
517                         continue;
518                 std::stringstream s;
519                 s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha);
520                 tiles[i].name = s.str();
521         }
522 }
523
524 void ContentFeatures::deSerialize(std::istream &is)
525 {
526         // version detection
527         int version = readU8(is);
528         if (version < 12)
529                 throw SerializationError("unsupported ContentFeatures version");
530
531         // general
532         name = deSerializeString(is);
533         groups.clear();
534         u32 groups_size = readU16(is);
535         for (u32 i = 0; i < groups_size; i++) {
536                 std::string name = deSerializeString(is);
537                 int value = readS16(is);
538                 groups[name] = value;
539         }
540         param_type = (enum ContentParamType) readU8(is);
541         param_type_2 = (enum ContentParamType2) readU8(is);
542
543         // visual
544         drawtype = (enum NodeDrawType) readU8(is);
545         mesh = deSerializeString(is);
546         visual_scale = readF1000(is);
547         if (readU8(is) != 6)
548                 throw SerializationError("unsupported tile count");
549         for (TileDef &td : tiledef)
550                 td.deSerialize(is, version, drawtype);
551         for (TileDef &td : tiledef_overlay)
552                 td.deSerialize(is, version, drawtype);
553         if (readU8(is) != CF_SPECIAL_COUNT)
554                 throw SerializationError("unsupported CF_SPECIAL_COUNT");
555         for (TileDef &td : tiledef_special)
556                 td.deSerialize(is, version, drawtype);
557         alpha = readU8(is);
558         color.setRed(readU8(is));
559         color.setGreen(readU8(is));
560         color.setBlue(readU8(is));
561         palette_name = deSerializeString(is);
562         waving = readU8(is);
563         connect_sides = readU8(is);
564         u16 connects_to_size = readU16(is);
565         connects_to_ids.clear();
566         for (u16 i = 0; i < connects_to_size; i++)
567                 connects_to_ids.push_back(readU16(is));
568         post_effect_color.setAlpha(readU8(is));
569         post_effect_color.setRed(readU8(is));
570         post_effect_color.setGreen(readU8(is));
571         post_effect_color.setBlue(readU8(is));
572         leveled = readU8(is);
573
574         // lighting-related
575         light_propagates = readU8(is);
576         sunlight_propagates = readU8(is);
577         light_source = readU8(is);
578         light_source = MYMIN(light_source, LIGHT_MAX);
579
580         // map generation
581         is_ground_content = readU8(is);
582
583         // interaction
584         walkable = readU8(is);
585         pointable = readU8(is);
586         diggable = readU8(is);
587         climbable = readU8(is);
588         buildable_to = readU8(is);
589         rightclickable = readU8(is);
590         damage_per_second = readU32(is);
591
592         // liquid
593         liquid_type = (enum LiquidType) readU8(is);
594         liquid_alternative_flowing = deSerializeString(is);
595         liquid_alternative_source = deSerializeString(is);
596         liquid_viscosity = readU8(is);
597         liquid_renewable = readU8(is);
598         liquid_range = readU8(is);
599         drowning = readU8(is);
600         floodable = readU8(is);
601
602         // node boxes
603         node_box.deSerialize(is);
604         selection_box.deSerialize(is);
605         collision_box.deSerialize(is);
606
607         // sounds
608         deSerializeSimpleSoundSpec(sound_footstep, is, version);
609         deSerializeSimpleSoundSpec(sound_dig, is, version);
610         deSerializeSimpleSoundSpec(sound_dug, is, version);
611
612         // read legacy properties
613         legacy_facedir_simple = readU8(is);
614         legacy_wallmounted = readU8(is);
615
616         try {
617                 node_dig_prediction = deSerializeString(is);
618         } catch(SerializationError &e) {};
619 }
620
621 #ifndef SERVER
622 static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
623                 const TileSpec &tile, const TileDef &tiledef, video::SColor color,
624                 u8 material_type, u32 shader_id, bool backface_culling,
625                 const TextureSettings &tsettings)
626 {
627         layer->shader_id     = shader_id;
628         layer->texture       = tsrc->getTextureForMesh(tiledef.name, &layer->texture_id);
629         layer->material_type = material_type;
630
631         bool has_scale = tiledef.scale > 0;
632         if (((tsettings.autoscale_mode == AUTOSCALE_ENABLE) && !has_scale) ||
633                         (tsettings.autoscale_mode == AUTOSCALE_FORCE)) {
634                 auto texture_size = layer->texture->getOriginalSize();
635                 float base_size = tsettings.node_texture_size;
636                 float size = std::fmin(texture_size.Width, texture_size.Height);
637                 layer->scale = std::fmax(base_size, size) / base_size;
638         } else if (has_scale) {
639                 layer->scale = tiledef.scale;
640         } else {
641                 layer->scale = 1;
642         }
643         if (!tile.world_aligned)
644                 layer->scale = 1;
645
646         // Normal texture and shader flags texture
647         if (tsettings.use_normal_texture) {
648                 layer->normal_texture = tsrc->getNormalTexture(tiledef.name);
649         }
650         layer->flags_texture = tsrc->getShaderFlagsTexture(layer->normal_texture ? true : false);
651
652         // Material flags
653         layer->material_flags = 0;
654         if (backface_culling)
655                 layer->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
656         if (tiledef.animation.type != TAT_NONE)
657                 layer->material_flags |= MATERIAL_FLAG_ANIMATION;
658         if (tiledef.tileable_horizontal)
659                 layer->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
660         if (tiledef.tileable_vertical)
661                 layer->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
662
663         // Color
664         layer->has_color = tiledef.has_color;
665         if (tiledef.has_color)
666                 layer->color = tiledef.color;
667         else
668                 layer->color = color;
669
670         // Animation parameters
671         int frame_count = 1;
672         if (layer->material_flags & MATERIAL_FLAG_ANIMATION) {
673                 int frame_length_ms;
674                 tiledef.animation.determineParams(layer->texture->getOriginalSize(),
675                                 &frame_count, &frame_length_ms, NULL);
676                 layer->animation_frame_count = frame_count;
677                 layer->animation_frame_length_ms = frame_length_ms;
678         }
679
680         if (frame_count == 1) {
681                 layer->material_flags &= ~MATERIAL_FLAG_ANIMATION;
682         } else {
683                 std::ostringstream os(std::ios::binary);
684                 if (!layer->frames) {
685                         layer->frames = std::make_shared<std::vector<FrameSpec>>();
686                 }
687                 layer->frames->resize(frame_count);
688
689                 for (int i = 0; i < frame_count; i++) {
690
691                         FrameSpec frame;
692
693                         os.str("");
694                         os << tiledef.name;
695                         tiledef.animation.getTextureModifer(os,
696                                         layer->texture->getOriginalSize(), i);
697
698                         frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
699                         if (layer->normal_texture)
700                                 frame.normal_texture = tsrc->getNormalTexture(os.str());
701                         frame.flags_texture = layer->flags_texture;
702                         (*layer->frames)[i] = frame;
703                 }
704         }
705 }
706 #endif
707
708 #ifndef SERVER
709 bool isWorldAligned(AlignStyle style, WorldAlignMode mode, NodeDrawType drawtype)
710 {
711         if (style == ALIGN_STYLE_WORLD)
712                 return true;
713         if (mode == WORLDALIGN_DISABLE)
714                 return false;
715         if (style == ALIGN_STYLE_USER_DEFINED)
716                 return true;
717         if (drawtype == NDT_NORMAL)
718                 return mode >= WORLDALIGN_FORCE;
719         if (drawtype == NDT_NODEBOX)
720                 return mode >= WORLDALIGN_FORCE_NODEBOX;
721         return false;
722 }
723
724 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
725         scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
726 {
727         // minimap pixel color - the average color of a texture
728         if (tsettings.enable_minimap && !tiledef[0].name.empty())
729                 minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
730
731         // Figure out the actual tiles to use
732         TileDef tdef[6];
733         for (u32 j = 0; j < 6; j++) {
734                 tdef[j] = tiledef[j];
735                 if (tdef[j].name.empty())
736                         tdef[j].name = "unknown_node.png";
737         }
738         // also the overlay tiles
739         TileDef tdef_overlay[6];
740         for (u32 j = 0; j < 6; j++)
741                 tdef_overlay[j] = tiledef_overlay[j];
742         // also the special tiles
743         TileDef tdef_spec[6];
744         for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
745                 tdef_spec[j] = tiledef_special[j];
746
747         bool is_liquid = false;
748
749         u8 material_type = (alpha == 255) ?
750                 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
751
752         switch (drawtype) {
753         default:
754         case NDT_NORMAL:
755                 material_type = (alpha == 255) ?
756                         TILE_MATERIAL_OPAQUE : TILE_MATERIAL_ALPHA;
757                 solidness = 2;
758                 break;
759         case NDT_AIRLIKE:
760                 solidness = 0;
761                 break;
762         case NDT_LIQUID:
763                 assert(liquid_type == LIQUID_SOURCE);
764                 if (tsettings.opaque_water)
765                         alpha = 255;
766                 solidness = 1;
767                 is_liquid = true;
768                 break;
769         case NDT_FLOWINGLIQUID:
770                 assert(liquid_type == LIQUID_FLOWING);
771                 solidness = 0;
772                 if (tsettings.opaque_water)
773                         alpha = 255;
774                 is_liquid = true;
775                 break;
776         case NDT_GLASSLIKE:
777                 solidness = 0;
778                 visual_solidness = 1;
779                 break;
780         case NDT_GLASSLIKE_FRAMED:
781                 solidness = 0;
782                 visual_solidness = 1;
783                 break;
784         case NDT_GLASSLIKE_FRAMED_OPTIONAL:
785                 solidness = 0;
786                 visual_solidness = 1;
787                 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
788                 break;
789         case NDT_ALLFACES:
790                 solidness = 0;
791                 visual_solidness = 1;
792                 break;
793         case NDT_ALLFACES_OPTIONAL:
794                 if (tsettings.leaves_style == LEAVES_FANCY) {
795                         drawtype = NDT_ALLFACES;
796                         solidness = 0;
797                         visual_solidness = 1;
798                 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
799                         for (u32 j = 0; j < 6; j++) {
800                                 if (!tdef_spec[j].name.empty())
801                                         tdef[j].name = tdef_spec[j].name;
802                         }
803                         drawtype = NDT_GLASSLIKE;
804                         solidness = 0;
805                         visual_solidness = 1;
806                 } else {
807                         drawtype = NDT_NORMAL;
808                         solidness = 2;
809                         for (TileDef &td : tdef)
810                                 td.name += std::string("^[noalpha");
811                 }
812                 if (waving >= 1)
813                         material_type = TILE_MATERIAL_WAVING_LEAVES;
814                 break;
815         case NDT_PLANTLIKE:
816                 solidness = 0;
817                 if (waving >= 1)
818                         material_type = TILE_MATERIAL_WAVING_PLANTS;
819                 break;
820         case NDT_FIRELIKE:
821                 solidness = 0;
822                 break;
823         case NDT_MESH:
824         case NDT_NODEBOX:
825                 solidness = 0;
826                 if (waving == 1)
827                         material_type = TILE_MATERIAL_WAVING_PLANTS;
828                 else if (waving == 2)
829                         material_type = TILE_MATERIAL_WAVING_LEAVES;
830                 break;
831         case NDT_TORCHLIKE:
832         case NDT_SIGNLIKE:
833         case NDT_FENCELIKE:
834         case NDT_RAILLIKE:
835                 solidness = 0;
836                 break;
837         case NDT_PLANTLIKE_ROOTED:
838                 solidness = 2;
839                 break;
840         }
841
842         if (is_liquid) {
843                 // Vertex alpha is no longer supported, correct if necessary.
844                 correctAlpha(tdef, 6);
845                 correctAlpha(tdef_overlay, 6);
846                 correctAlpha(tdef_spec, CF_SPECIAL_COUNT);
847                 material_type = (alpha == 255) ?
848                         TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
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 // IWritableNodeDefManager
1227 content_t NodeDefManager::set(const std::string &name, const ContentFeatures &def)
1228 {
1229         // Pre-conditions
1230         assert(name != "");
1231         assert(name != "ignore");
1232         assert(name == def.name);
1233
1234         content_t id = CONTENT_IGNORE;
1235         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1236                 // Get new id
1237                 id = allocateId();
1238                 if (id == CONTENT_IGNORE) {
1239                         warningstream << "NodeDefManager: Absolute "
1240                                 "limit reached" << std::endl;
1241                         return CONTENT_IGNORE;
1242                 }
1243                 assert(id != CONTENT_IGNORE);
1244                 addNameIdMapping(id, name);
1245         }
1246         m_content_features[id] = def;
1247         verbosestream << "NodeDefManager: registering content id \"" << id
1248                 << "\": name=\"" << def.name << "\""<<std::endl;
1249
1250         getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1251         fixSelectionBoxIntUnion();
1252         // Add this content to the list of all groups it belongs to
1253         // FIXME: This should remove a node from groups it no longer
1254         // belongs to when a node is re-registered
1255         for (const auto &group : def.groups) {
1256                 const std::string &group_name = group.first;
1257                 m_group_to_items[group_name].push_back(id);
1258         }
1259         return id;
1260 }
1261
1262
1263 content_t NodeDefManager::allocateDummy(const std::string &name)
1264 {
1265         assert(name != "");     // Pre-condition
1266         ContentFeatures f;
1267         f.name = name;
1268         return set(name, f);
1269 }
1270
1271
1272 void NodeDefManager::removeNode(const std::string &name)
1273 {
1274         // Pre-condition
1275         assert(name != "");
1276
1277         // Erase name from name ID mapping
1278         content_t id = CONTENT_IGNORE;
1279         if (m_name_id_mapping.getId(name, id)) {
1280                 m_name_id_mapping.eraseName(name);
1281                 m_name_id_mapping_with_aliases.erase(name);
1282         }
1283
1284         // Erase node content from all groups it belongs to
1285         for (std::unordered_map<std::string, std::vector<content_t>>::iterator iter_groups =
1286                         m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1287                 std::vector<content_t> &items = iter_groups->second;
1288                 items.erase(std::remove(items.begin(), items.end(), id), items.end());
1289
1290                 // Check if group is empty
1291                 if (items.empty())
1292                         m_group_to_items.erase(iter_groups++);
1293                 else
1294                         ++iter_groups;
1295         }
1296 }
1297
1298
1299 void NodeDefManager::updateAliases(IItemDefManager *idef)
1300 {
1301         std::set<std::string> all;
1302         idef->getAll(all);
1303         m_name_id_mapping_with_aliases.clear();
1304         for (const std::string &name : all) {
1305                 const std::string &convert_to = idef->getAlias(name);
1306                 content_t id;
1307                 if (m_name_id_mapping.getId(convert_to, id)) {
1308                         m_name_id_mapping_with_aliases.insert(
1309                                 std::make_pair(name, id));
1310                 }
1311         }
1312 }
1313
1314 void NodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1315 {
1316         infostream << "NodeDefManager::applyTextureOverrides(): Applying "
1317                 "overrides to textures from " << override_filepath << std::endl;
1318
1319         std::ifstream infile(override_filepath.c_str());
1320         std::string line;
1321         int line_c = 0;
1322         while (std::getline(infile, line)) {
1323                 line_c++;
1324                 if (trim(line).empty())
1325                         continue;
1326                 std::vector<std::string> splitted = str_split(line, ' ');
1327                 if (splitted.size() != 3) {
1328                         errorstream << override_filepath
1329                                 << ":" << line_c << " Could not apply texture override \""
1330                                 << line << "\": Syntax error" << std::endl;
1331                         continue;
1332                 }
1333
1334                 content_t id;
1335                 if (!getId(splitted[0], id))
1336                         continue; // Ignore unknown node
1337
1338                 ContentFeatures &nodedef = m_content_features[id];
1339
1340                 if (splitted[1] == "top")
1341                         nodedef.tiledef[0].name = splitted[2];
1342                 else if (splitted[1] == "bottom")
1343                         nodedef.tiledef[1].name = splitted[2];
1344                 else if (splitted[1] == "right")
1345                         nodedef.tiledef[2].name = splitted[2];
1346                 else if (splitted[1] == "left")
1347                         nodedef.tiledef[3].name = splitted[2];
1348                 else if (splitted[1] == "back")
1349                         nodedef.tiledef[4].name = splitted[2];
1350                 else if (splitted[1] == "front")
1351                         nodedef.tiledef[5].name = splitted[2];
1352                 else if (splitted[1] == "all" || splitted[1] == "*")
1353                         for (TileDef &i : nodedef.tiledef)
1354                                 i.name = splitted[2];
1355                 else if (splitted[1] == "sides")
1356                         for (int i = 2; i < 6; i++)
1357                                 nodedef.tiledef[i].name = splitted[2];
1358                 else {
1359                         errorstream << override_filepath
1360                                 << ":" << line_c << " Could not apply texture override \""
1361                                 << line << "\": Unknown node side \""
1362                                 << splitted[1] << "\"" << std::endl;
1363                         continue;
1364                 }
1365         }
1366 }
1367
1368 void NodeDefManager::updateTextures(IGameDef *gamedef,
1369         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1370         void *progress_callback_args)
1371 {
1372 #ifndef SERVER
1373         infostream << "NodeDefManager::updateTextures(): Updating "
1374                 "textures in node definitions" << std::endl;
1375
1376         Client *client = (Client *)gamedef;
1377         ITextureSource *tsrc = client->tsrc();
1378         IShaderSource *shdsrc = client->getShaderSource();
1379         scene::IMeshManipulator *meshmanip =
1380                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1381         TextureSettings tsettings;
1382         tsettings.readSettings();
1383
1384         u32 size = m_content_features.size();
1385
1386         for (u32 i = 0; i < size; i++) {
1387                 ContentFeatures *f = &(m_content_features[i]);
1388                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1389                 progress_callback(progress_callback_args, i, size);
1390         }
1391 #endif
1392 }
1393
1394 void NodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1395 {
1396         writeU8(os, 1); // version
1397         u16 count = 0;
1398         std::ostringstream os2(std::ios::binary);
1399         for (u32 i = 0; i < m_content_features.size(); i++) {
1400                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1401                                 || i == CONTENT_UNKNOWN)
1402                         continue;
1403                 const ContentFeatures *f = &m_content_features[i];
1404                 if (f->name.empty())
1405                         continue;
1406                 writeU16(os2, i);
1407                 // Wrap it in a string to allow different lengths without
1408                 // strict version incompatibilities
1409                 std::ostringstream wrapper_os(std::ios::binary);
1410                 f->serialize(wrapper_os, protocol_version);
1411                 os2<<serializeString(wrapper_os.str());
1412
1413                 // must not overflow
1414                 u16 next = count + 1;
1415                 FATAL_ERROR_IF(next < count, "Overflow");
1416                 count++;
1417         }
1418         writeU16(os, count);
1419         os << serializeLongString(os2.str());
1420 }
1421
1422
1423 void NodeDefManager::deSerialize(std::istream &is)
1424 {
1425         clear();
1426         int version = readU8(is);
1427         if (version != 1)
1428                 throw SerializationError("unsupported NodeDefinitionManager version");
1429         u16 count = readU16(is);
1430         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1431         ContentFeatures f;
1432         for (u16 n = 0; n < count; n++) {
1433                 u16 i = readU16(is2);
1434
1435                 // Read it from the string wrapper
1436                 std::string wrapper = deSerializeString(is2);
1437                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1438                 f.deSerialize(wrapper_is);
1439
1440                 // Check error conditions
1441                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1442                         warningstream << "NodeDefManager::deSerialize(): "
1443                                 "not changing builtin node " << i << std::endl;
1444                         continue;
1445                 }
1446                 if (f.name.empty()) {
1447                         warningstream << "NodeDefManager::deSerialize(): "
1448                                 "received empty name" << std::endl;
1449                         continue;
1450                 }
1451
1452                 // Ignore aliases
1453                 u16 existing_id;
1454                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1455                         warningstream << "NodeDefManager::deSerialize(): "
1456                                 "already defined with different ID: " << f.name << std::endl;
1457                         continue;
1458                 }
1459
1460                 // All is ok, add node definition with the requested ID
1461                 if (i >= m_content_features.size())
1462                         m_content_features.resize((u32)(i) + 1);
1463                 m_content_features[i] = f;
1464                 addNameIdMapping(i, f.name);
1465                 verbosestream << "deserialized " << f.name << std::endl;
1466
1467                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1468                 fixSelectionBoxIntUnion();
1469         }
1470 }
1471
1472
1473 void NodeDefManager::addNameIdMapping(content_t i, std::string name)
1474 {
1475         m_name_id_mapping.set(i, name);
1476         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1477 }
1478
1479
1480 NodeDefManager *createNodeDefManager()
1481 {
1482         return new NodeDefManager();
1483 }
1484
1485
1486 void NodeDefManager::pendNodeResolve(NodeResolver *nr) const
1487 {
1488         nr->m_ndef = this;
1489         if (m_node_registration_complete)
1490                 nr->nodeResolveInternal();
1491         else
1492                 m_pending_resolve_callbacks.push_back(nr);
1493 }
1494
1495
1496 bool NodeDefManager::cancelNodeResolveCallback(NodeResolver *nr) const
1497 {
1498         size_t len = m_pending_resolve_callbacks.size();
1499         for (size_t i = 0; i != len; i++) {
1500                 if (nr != m_pending_resolve_callbacks[i])
1501                         continue;
1502
1503                 len--;
1504                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1505                 m_pending_resolve_callbacks.resize(len);
1506                 return true;
1507         }
1508
1509         return false;
1510 }
1511
1512
1513 void NodeDefManager::runNodeResolveCallbacks()
1514 {
1515         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1516                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1517                 nr->nodeResolveInternal();
1518         }
1519
1520         m_pending_resolve_callbacks.clear();
1521 }
1522
1523
1524 void NodeDefManager::resetNodeResolveState()
1525 {
1526         m_node_registration_complete = false;
1527         m_pending_resolve_callbacks.clear();
1528 }
1529
1530 void NodeDefManager::mapNodeboxConnections()
1531 {
1532         for (ContentFeatures &f : m_content_features) {
1533                 if (f.drawtype != NDT_NODEBOX || f.node_box.type != NODEBOX_CONNECTED)
1534                         continue;
1535
1536                 for (const std::string &name : f.connects_to) {
1537                         getIds(name, f.connects_to_ids);
1538                 }
1539         }
1540 }
1541
1542 bool NodeDefManager::nodeboxConnects(MapNode from, MapNode to,
1543         u8 connect_face) const
1544 {
1545         const ContentFeatures &f1 = get(from);
1546
1547         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1548                 return false;
1549
1550         // lookup target in connected set
1551         if (!CONTAINS(f1.connects_to_ids, to.param0))
1552                 return false;
1553
1554         const ContentFeatures &f2 = get(to);
1555
1556         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1557                 // ignores actually looking if back connection exists
1558                 return CONTAINS(f2.connects_to_ids, from.param0);
1559
1560         // does to node declare usable faces?
1561         if (f2.connect_sides > 0) {
1562                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1563                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1564                                 && (connect_face >= 4)) {
1565                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1566                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1567                                 0, // 4 - back
1568                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1569                                 0, // 8 - right
1570                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1571                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1572                                 0, // 16 - front
1573                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1574                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1575                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1576                                 };
1577                         return (f2.connect_sides
1578                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1579                 }
1580                 return (f2.connect_sides & connect_face);
1581         }
1582         // the target is just a regular node, so connect no matter back connection
1583         return true;
1584 }
1585
1586 ////
1587 //// NodeResolver
1588 ////
1589
1590 NodeResolver::NodeResolver()
1591 {
1592         m_nodenames.reserve(16);
1593         m_nnlistsizes.reserve(4);
1594 }
1595
1596
1597 NodeResolver::~NodeResolver()
1598 {
1599         if (!m_resolve_done && m_ndef)
1600                 m_ndef->cancelNodeResolveCallback(this);
1601 }
1602
1603
1604 void NodeResolver::nodeResolveInternal()
1605 {
1606         m_nodenames_idx   = 0;
1607         m_nnlistsizes_idx = 0;
1608
1609         resolveNodeNames();
1610         m_resolve_done = true;
1611
1612         m_nodenames.clear();
1613         m_nnlistsizes.clear();
1614 }
1615
1616
1617 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1618         const std::string &node_alt, content_t c_fallback, bool error_on_fallback)
1619 {
1620         if (m_nodenames_idx == m_nodenames.size()) {
1621                 *result_out = c_fallback;
1622                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1623                 return false;
1624         }
1625
1626         content_t c;
1627         std::string name = m_nodenames[m_nodenames_idx++];
1628
1629         bool success = m_ndef->getId(name, c);
1630         if (!success && !node_alt.empty()) {
1631                 name = node_alt;
1632                 success = m_ndef->getId(name, c);
1633         }
1634
1635         if (!success) {
1636                 if (error_on_fallback)
1637                         errorstream << "NodeResolver: failed to resolve node name '" << name
1638                                 << "'." << std::endl;
1639                 c = c_fallback;
1640         }
1641
1642         *result_out = c;
1643         return success;
1644 }
1645
1646
1647 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1648         bool all_required, content_t c_fallback)
1649 {
1650         bool success = true;
1651
1652         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1653                 errorstream << "NodeResolver: no more node lists" << std::endl;
1654                 return false;
1655         }
1656
1657         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1658
1659         while (length--) {
1660                 if (m_nodenames_idx == m_nodenames.size()) {
1661                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1662                         return false;
1663                 }
1664
1665                 content_t c;
1666                 std::string &name = m_nodenames[m_nodenames_idx++];
1667
1668                 if (name.substr(0,6) != "group:") {
1669                         if (m_ndef->getId(name, c)) {
1670                                 result_out->push_back(c);
1671                         } else if (all_required) {
1672                                 errorstream << "NodeResolver: failed to resolve node name '"
1673                                         << name << "'." << std::endl;
1674                                 result_out->push_back(c_fallback);
1675                                 success = false;
1676                         }
1677                 } else {
1678                         m_ndef->getIds(name, *result_out);
1679                 }
1680         }
1681
1682         return success;
1683 }