]> git.lizzy.rs Git - minetest.git/blob - src/nodedef.cpp
Connected Nodeboxes: Add `disconnected` boxes
[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         CNodeDefManager
935 */
936
937 class CNodeDefManager: public IWritableNodeDefManager {
938 public:
939         CNodeDefManager();
940         virtual ~CNodeDefManager();
941         void clear();
942
943         inline virtual const ContentFeatures& get(content_t c) const;
944         inline virtual const ContentFeatures& get(const MapNode &n) const;
945         virtual bool getId(const std::string &name, content_t &result) const;
946         virtual content_t getId(const std::string &name) const;
947         virtual bool getIds(const std::string &name, std::vector<content_t> &result) const;
948         virtual const ContentFeatures& get(const std::string &name) const;
949         content_t allocateId();
950         virtual content_t set(const std::string &name, const ContentFeatures &def);
951         virtual content_t allocateDummy(const std::string &name);
952         virtual void removeNode(const std::string &name);
953         virtual void updateAliases(IItemDefManager *idef);
954         virtual void applyTextureOverrides(const std::string &override_filepath);
955         virtual void updateTextures(IGameDef *gamedef,
956                 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
957                 void *progress_cbk_args);
958         void serialize(std::ostream &os, u16 protocol_version) const;
959         void deSerialize(std::istream &is);
960
961         inline virtual void setNodeRegistrationStatus(bool completed);
962
963         virtual void pendNodeResolve(NodeResolver *nr);
964         virtual bool cancelNodeResolveCallback(NodeResolver *nr);
965         virtual void runNodeResolveCallbacks();
966         virtual void resetNodeResolveState();
967         virtual void mapNodeboxConnections();
968         virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
969         virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
970         {
971                 return m_selection_box_int_union;
972         }
973
974 private:
975         void addNameIdMapping(content_t i, std::string name);
976         /*!
977          * Recalculates m_selection_box_int_union based on
978          * m_selection_box_union.
979          */
980         void fixSelectionBoxIntUnion();
981
982         // Features indexed by id
983         std::vector<ContentFeatures> m_content_features;
984
985         // A mapping for fast converting back and forth between names and ids
986         NameIdMapping m_name_id_mapping;
987
988         // Like m_name_id_mapping, but only from names to ids, and includes
989         // item aliases too. Updated by updateAliases()
990         // Note: Not serialized.
991
992         std::unordered_map<std::string, content_t> m_name_id_mapping_with_aliases;
993
994         // A mapping from groups to a vector of content_ts that belong to it.
995         // Necessary for a direct lookup in getIds().
996         // Note: Not serialized.
997         std::unordered_map<std::string, std::vector<content_t>> m_group_to_items;
998
999         // Next possibly free id
1000         content_t m_next_id;
1001
1002         // NodeResolvers to callback once node registration has ended
1003         std::vector<NodeResolver *> m_pending_resolve_callbacks;
1004
1005         // True when all nodes have been registered
1006         bool m_node_registration_complete;
1007
1008         //! The union of all nodes' selection boxes.
1009         aabb3f m_selection_box_union;
1010         /*!
1011          * The smallest box in node coordinates that
1012          * contains all nodes' selection boxes.
1013          */
1014         core::aabbox3d<s16> m_selection_box_int_union;
1015 };
1016
1017
1018 CNodeDefManager::CNodeDefManager()
1019 {
1020         clear();
1021 }
1022
1023
1024 CNodeDefManager::~CNodeDefManager()
1025 {
1026 #ifndef SERVER
1027         for (ContentFeatures &f : m_content_features) {
1028                 for (auto &j : f.mesh_ptr) {
1029                         if (j)
1030                                 j->drop();
1031                 }
1032         }
1033 #endif
1034 }
1035
1036
1037 void CNodeDefManager::clear()
1038 {
1039         m_content_features.clear();
1040         m_name_id_mapping.clear();
1041         m_name_id_mapping_with_aliases.clear();
1042         m_group_to_items.clear();
1043         m_next_id = 0;
1044         m_selection_box_union.reset(0,0,0);
1045         m_selection_box_int_union.reset(0,0,0);
1046
1047         resetNodeResolveState();
1048
1049         u32 initial_length = 0;
1050         initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
1051         initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
1052         initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
1053         m_content_features.resize(initial_length);
1054
1055         // Set CONTENT_UNKNOWN
1056         {
1057                 ContentFeatures f;
1058                 f.name = "unknown";
1059                 // Insert directly into containers
1060                 content_t c = CONTENT_UNKNOWN;
1061                 m_content_features[c] = f;
1062                 addNameIdMapping(c, f.name);
1063         }
1064
1065         // Set CONTENT_AIR
1066         {
1067                 ContentFeatures f;
1068                 f.name                = "air";
1069                 f.drawtype            = NDT_AIRLIKE;
1070                 f.param_type          = CPT_LIGHT;
1071                 f.light_propagates    = true;
1072                 f.sunlight_propagates = true;
1073                 f.walkable            = false;
1074                 f.pointable           = false;
1075                 f.diggable            = false;
1076                 f.buildable_to        = true;
1077                 f.floodable           = true;
1078                 f.is_ground_content   = true;
1079                 // Insert directly into containers
1080                 content_t c = CONTENT_AIR;
1081                 m_content_features[c] = f;
1082                 addNameIdMapping(c, f.name);
1083         }
1084
1085         // Set CONTENT_IGNORE
1086         {
1087                 ContentFeatures f;
1088                 f.name                = "ignore";
1089                 f.drawtype            = NDT_AIRLIKE;
1090                 f.param_type          = CPT_NONE;
1091                 f.light_propagates    = false;
1092                 f.sunlight_propagates = false;
1093                 f.walkable            = false;
1094                 f.pointable           = false;
1095                 f.diggable            = false;
1096                 f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
1097                 f.is_ground_content   = true;
1098                 // Insert directly into containers
1099                 content_t c = CONTENT_IGNORE;
1100                 m_content_features[c] = f;
1101                 addNameIdMapping(c, f.name);
1102         }
1103 }
1104
1105
1106 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1107 {
1108         return c < m_content_features.size()
1109                         ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1110 }
1111
1112
1113 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1114 {
1115         return get(n.getContent());
1116 }
1117
1118
1119 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1120 {
1121         std::unordered_map<std::string, content_t>::const_iterator
1122                 i = m_name_id_mapping_with_aliases.find(name);
1123         if(i == m_name_id_mapping_with_aliases.end())
1124                 return false;
1125         result = i->second;
1126         return true;
1127 }
1128
1129
1130 content_t CNodeDefManager::getId(const std::string &name) const
1131 {
1132         content_t id = CONTENT_IGNORE;
1133         getId(name, id);
1134         return id;
1135 }
1136
1137
1138 bool CNodeDefManager::getIds(const std::string &name,
1139                 std::vector<content_t> &result) const
1140 {
1141         //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1142         if (name.substr(0,6) != "group:") {
1143                 content_t id = CONTENT_IGNORE;
1144                 bool exists = getId(name, id);
1145                 if (exists)
1146                         result.push_back(id);
1147                 return exists;
1148         }
1149         std::string group = name.substr(6);
1150
1151         std::unordered_map<std::string, std::vector<content_t>>::const_iterator
1152                 i = m_group_to_items.find(group);
1153         if (i == m_group_to_items.end())
1154                 return true;
1155
1156         const std::vector<content_t> &items = i->second;
1157         result.insert(result.end(), items.begin(), items.end());
1158         //printf("getIds: %dus\n", t.stop());
1159         return true;
1160 }
1161
1162
1163 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1164 {
1165         content_t id = CONTENT_UNKNOWN;
1166         getId(name, id);
1167         return get(id);
1168 }
1169
1170
1171 // returns CONTENT_IGNORE if no free ID found
1172 content_t CNodeDefManager::allocateId()
1173 {
1174         for (content_t id = m_next_id;
1175                         id >= m_next_id; // overflow?
1176                         ++id) {
1177                 while (id >= m_content_features.size()) {
1178                         m_content_features.emplace_back();
1179                 }
1180                 const ContentFeatures &f = m_content_features[id];
1181                 if (f.name.empty()) {
1182                         m_next_id = id + 1;
1183                         return id;
1184                 }
1185         }
1186         // If we arrive here, an overflow occurred in id.
1187         // That means no ID was found
1188         return CONTENT_IGNORE;
1189 }
1190
1191
1192 /*!
1193  * Returns the smallest box that contains all boxes
1194  * in the vector. Box_union is expanded.
1195  * @param[in]      boxes     the vector containing the boxes
1196  * @param[in, out] box_union the union of the arguments
1197  */
1198 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1199 {
1200         for (const aabb3f &box : boxes) {
1201                 box_union->addInternalBox(box);
1202         }
1203 }
1204
1205
1206 /*!
1207  * Returns a box that contains the nodebox in every case.
1208  * The argument node_union is expanded.
1209  * @param[in]      nodebox  the nodebox to be measured
1210  * @param[in]      features  used to decide whether the nodebox
1211  * can be rotated
1212  * @param[in, out] box_union the union of the arguments
1213  */
1214 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1215         aabb3f *box_union)
1216 {
1217         switch(nodebox.type) {
1218                 case NODEBOX_FIXED:
1219                 case NODEBOX_LEVELED: {
1220                         // Raw union
1221                         aabb3f half_processed(0, 0, 0, 0, 0, 0);
1222                         boxVectorUnion(nodebox.fixed, &half_processed);
1223                         // Set leveled boxes to maximal
1224                         if (nodebox.type == NODEBOX_LEVELED) {
1225                                 half_processed.MaxEdge.Y = +BS / 2;
1226                         }
1227                         if (features.param_type_2 == CPT2_FACEDIR ||
1228                                         features.param_type_2 == CPT2_COLORED_FACEDIR) {
1229                                 // Get maximal coordinate
1230                                 f32 coords[] = {
1231                                         fabsf(half_processed.MinEdge.X),
1232                                         fabsf(half_processed.MinEdge.Y),
1233                                         fabsf(half_processed.MinEdge.Z),
1234                                         fabsf(half_processed.MaxEdge.X),
1235                                         fabsf(half_processed.MaxEdge.Y),
1236                                         fabsf(half_processed.MaxEdge.Z) };
1237                                 f32 max = 0;
1238                                 for (float coord : coords) {
1239                                         if (max < coord) {
1240                                                 max = coord;
1241                                         }
1242                                 }
1243                                 // Add the union of all possible rotated boxes
1244                                 box_union->addInternalPoint(-max, -max, -max);
1245                                 box_union->addInternalPoint(+max, +max, +max);
1246                         } else {
1247                                 box_union->addInternalBox(half_processed);
1248                         }
1249                         break;
1250                 }
1251                 case NODEBOX_WALLMOUNTED: {
1252                         // Add fix boxes
1253                         box_union->addInternalBox(nodebox.wall_top);
1254                         box_union->addInternalBox(nodebox.wall_bottom);
1255                         // Find maximal coordinate in the X-Z plane
1256                         f32 coords[] = {
1257                                 fabsf(nodebox.wall_side.MinEdge.X),
1258                                 fabsf(nodebox.wall_side.MinEdge.Z),
1259                                 fabsf(nodebox.wall_side.MaxEdge.X),
1260                                 fabsf(nodebox.wall_side.MaxEdge.Z) };
1261                         f32 max = 0;
1262                         for (float coord : coords) {
1263                                 if (max < coord) {
1264                                         max = coord;
1265                                 }
1266                         }
1267                         // Add the union of all possible rotated boxes
1268                         box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1269                         box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1270                         break;
1271                 }
1272                 case NODEBOX_CONNECTED: {
1273                         // Add all possible connected boxes
1274                         boxVectorUnion(nodebox.fixed,               box_union);
1275                         boxVectorUnion(nodebox.connect_top,         box_union);
1276                         boxVectorUnion(nodebox.connect_bottom,      box_union);
1277                         boxVectorUnion(nodebox.connect_front,       box_union);
1278                         boxVectorUnion(nodebox.connect_left,        box_union);
1279                         boxVectorUnion(nodebox.connect_back,        box_union);
1280                         boxVectorUnion(nodebox.connect_right,       box_union);
1281                         boxVectorUnion(nodebox.disconnected_top,    box_union);
1282                         boxVectorUnion(nodebox.disconnected_bottom, box_union);
1283                         boxVectorUnion(nodebox.disconnected_front,  box_union);
1284                         boxVectorUnion(nodebox.disconnected_left,   box_union);
1285                         boxVectorUnion(nodebox.disconnected_back,   box_union);
1286                         boxVectorUnion(nodebox.disconnected_right,  box_union);
1287                         boxVectorUnion(nodebox.disconnected,        box_union);
1288                         boxVectorUnion(nodebox.disconnected_sides,  box_union);
1289                         break;
1290                 }
1291                 default: {
1292                         // NODEBOX_REGULAR
1293                         box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1294                         box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1295                 }
1296         }
1297 }
1298
1299
1300 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1301 {
1302         m_selection_box_int_union.MinEdge.X = floorf(
1303                 m_selection_box_union.MinEdge.X / BS + 0.5f);
1304         m_selection_box_int_union.MinEdge.Y = floorf(
1305                 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1306         m_selection_box_int_union.MinEdge.Z = floorf(
1307                 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1308         m_selection_box_int_union.MaxEdge.X = ceilf(
1309                 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1310         m_selection_box_int_union.MaxEdge.Y = ceilf(
1311                 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1312         m_selection_box_int_union.MaxEdge.Z = ceilf(
1313                 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1314 }
1315
1316
1317 // IWritableNodeDefManager
1318 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1319 {
1320         // Pre-conditions
1321         assert(name != "");
1322         assert(name == def.name);
1323
1324         // Don't allow redefining ignore (but allow air and unknown)
1325         if (name == "ignore") {
1326                 warningstream << "NodeDefManager: Ignoring "
1327                         "CONTENT_IGNORE redefinition"<<std::endl;
1328                 return CONTENT_IGNORE;
1329         }
1330
1331         content_t id = CONTENT_IGNORE;
1332         if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1333                 // Get new id
1334                 id = allocateId();
1335                 if (id == CONTENT_IGNORE) {
1336                         warningstream << "NodeDefManager: Absolute "
1337                                 "limit reached" << std::endl;
1338                         return CONTENT_IGNORE;
1339                 }
1340                 assert(id != CONTENT_IGNORE);
1341                 addNameIdMapping(id, name);
1342         }
1343         m_content_features[id] = def;
1344         verbosestream << "NodeDefManager: registering content id \"" << id
1345                 << "\": name=\"" << def.name << "\""<<std::endl;
1346
1347         getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1348         fixSelectionBoxIntUnion();
1349         // Add this content to the list of all groups it belongs to
1350         // FIXME: This should remove a node from groups it no longer
1351         // belongs to when a node is re-registered
1352         for (const auto &group : def.groups) {
1353                 const std::string &group_name = group.first;
1354                 m_group_to_items[group_name].push_back(id);
1355         }
1356         return id;
1357 }
1358
1359
1360 content_t CNodeDefManager::allocateDummy(const std::string &name)
1361 {
1362         assert(name != "");     // Pre-condition
1363         ContentFeatures f;
1364         f.name = name;
1365         return set(name, f);
1366 }
1367
1368
1369 void CNodeDefManager::removeNode(const std::string &name)
1370 {
1371         // Pre-condition
1372         assert(name != "");
1373
1374         // Erase name from name ID mapping
1375         content_t id = CONTENT_IGNORE;
1376         if (m_name_id_mapping.getId(name, id)) {
1377                 m_name_id_mapping.eraseName(name);
1378                 m_name_id_mapping_with_aliases.erase(name);
1379         }
1380
1381         // Erase node content from all groups it belongs to
1382         for (std::unordered_map<std::string, std::vector<content_t>>::iterator iter_groups =
1383                         m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1384                 std::vector<content_t> &items = iter_groups->second;
1385                 items.erase(std::remove(items.begin(), items.end(), id), items.end());
1386
1387                 // Check if group is empty
1388                 if (items.empty())
1389                         m_group_to_items.erase(iter_groups++);
1390                 else
1391                         ++iter_groups;
1392         }
1393 }
1394
1395
1396 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1397 {
1398         std::set<std::string> all;
1399         idef->getAll(all);
1400         m_name_id_mapping_with_aliases.clear();
1401         for (const std::string &name : all) {
1402                 const std::string &convert_to = idef->getAlias(name);
1403                 content_t id;
1404                 if (m_name_id_mapping.getId(convert_to, id)) {
1405                         m_name_id_mapping_with_aliases.insert(
1406                                 std::make_pair(name, id));
1407                 }
1408         }
1409 }
1410
1411 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1412 {
1413         infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1414                 "overrides to textures from " << override_filepath << std::endl;
1415
1416         std::ifstream infile(override_filepath.c_str());
1417         std::string line;
1418         int line_c = 0;
1419         while (std::getline(infile, line)) {
1420                 line_c++;
1421                 if (trim(line).empty())
1422                         continue;
1423                 std::vector<std::string> splitted = str_split(line, ' ');
1424                 if (splitted.size() != 3) {
1425                         errorstream << override_filepath
1426                                 << ":" << line_c << " Could not apply texture override \""
1427                                 << line << "\": Syntax error" << std::endl;
1428                         continue;
1429                 }
1430
1431                 content_t id;
1432                 if (!getId(splitted[0], id))
1433                         continue; // Ignore unknown node
1434
1435                 ContentFeatures &nodedef = m_content_features[id];
1436
1437                 if (splitted[1] == "top")
1438                         nodedef.tiledef[0].name = splitted[2];
1439                 else if (splitted[1] == "bottom")
1440                         nodedef.tiledef[1].name = splitted[2];
1441                 else if (splitted[1] == "right")
1442                         nodedef.tiledef[2].name = splitted[2];
1443                 else if (splitted[1] == "left")
1444                         nodedef.tiledef[3].name = splitted[2];
1445                 else if (splitted[1] == "back")
1446                         nodedef.tiledef[4].name = splitted[2];
1447                 else if (splitted[1] == "front")
1448                         nodedef.tiledef[5].name = splitted[2];
1449                 else if (splitted[1] == "all" || splitted[1] == "*")
1450                         for (TileDef &i : nodedef.tiledef)
1451                                 i.name = splitted[2];
1452                 else if (splitted[1] == "sides")
1453                         for (int i = 2; i < 6; i++)
1454                                 nodedef.tiledef[i].name = splitted[2];
1455                 else {
1456                         errorstream << override_filepath
1457                                 << ":" << line_c << " Could not apply texture override \""
1458                                 << line << "\": Unknown node side \""
1459                                 << splitted[1] << "\"" << std::endl;
1460                         continue;
1461                 }
1462         }
1463 }
1464
1465 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1466         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1467         void *progress_callback_args)
1468 {
1469 #ifndef SERVER
1470         infostream << "CNodeDefManager::updateTextures(): Updating "
1471                 "textures in node definitions" << std::endl;
1472
1473         Client *client = (Client *)gamedef;
1474         ITextureSource *tsrc = client->tsrc();
1475         IShaderSource *shdsrc = client->getShaderSource();
1476         scene::IMeshManipulator *meshmanip =
1477                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1478         TextureSettings tsettings;
1479         tsettings.readSettings();
1480
1481         u32 size = m_content_features.size();
1482
1483         for (u32 i = 0; i < size; i++) {
1484                 ContentFeatures *f = &(m_content_features[i]);
1485                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1486                 progress_callback(progress_callback_args, i, size);
1487         }
1488 #endif
1489 }
1490
1491 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1492 {
1493         writeU8(os, 1); // version
1494         u16 count = 0;
1495         std::ostringstream os2(std::ios::binary);
1496         for (u32 i = 0; i < m_content_features.size(); i++) {
1497                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1498                                 || i == CONTENT_UNKNOWN)
1499                         continue;
1500                 const ContentFeatures *f = &m_content_features[i];
1501                 if (f->name.empty())
1502                         continue;
1503                 writeU16(os2, i);
1504                 // Wrap it in a string to allow different lengths without
1505                 // strict version incompatibilities
1506                 std::ostringstream wrapper_os(std::ios::binary);
1507                 f->serialize(wrapper_os, protocol_version);
1508                 os2<<serializeString(wrapper_os.str());
1509
1510                 // must not overflow
1511                 u16 next = count + 1;
1512                 FATAL_ERROR_IF(next < count, "Overflow");
1513                 count++;
1514         }
1515         writeU16(os, count);
1516         os << serializeLongString(os2.str());
1517 }
1518
1519
1520 void CNodeDefManager::deSerialize(std::istream &is)
1521 {
1522         clear();
1523         int version = readU8(is);
1524         if (version != 1)
1525                 throw SerializationError("unsupported NodeDefinitionManager version");
1526         u16 count = readU16(is);
1527         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1528         ContentFeatures f;
1529         for (u16 n = 0; n < count; n++) {
1530                 u16 i = readU16(is2);
1531
1532                 // Read it from the string wrapper
1533                 std::string wrapper = deSerializeString(is2);
1534                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1535                 f.deSerialize(wrapper_is);
1536
1537                 // Check error conditions
1538                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1539                         warningstream << "NodeDefManager::deSerialize(): "
1540                                 "not changing builtin node " << i << std::endl;
1541                         continue;
1542                 }
1543                 if (f.name.empty()) {
1544                         warningstream << "NodeDefManager::deSerialize(): "
1545                                 "received empty name" << std::endl;
1546                         continue;
1547                 }
1548
1549                 // Ignore aliases
1550                 u16 existing_id;
1551                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1552                         warningstream << "NodeDefManager::deSerialize(): "
1553                                 "already defined with different ID: " << f.name << std::endl;
1554                         continue;
1555                 }
1556
1557                 // All is ok, add node definition with the requested ID
1558                 if (i >= m_content_features.size())
1559                         m_content_features.resize((u32)(i) + 1);
1560                 m_content_features[i] = f;
1561                 addNameIdMapping(i, f.name);
1562                 verbosestream << "deserialized " << f.name << std::endl;
1563
1564                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1565                 fixSelectionBoxIntUnion();
1566         }
1567 }
1568
1569
1570 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1571 {
1572         m_name_id_mapping.set(i, name);
1573         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1574 }
1575
1576
1577 IWritableNodeDefManager *createNodeDefManager()
1578 {
1579         return new CNodeDefManager();
1580 }
1581
1582 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1583 {
1584         m_node_registration_complete = completed;
1585 }
1586
1587
1588 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1589 {
1590         nr->m_ndef = this;
1591         if (m_node_registration_complete)
1592                 nr->nodeResolveInternal();
1593         else
1594                 m_pending_resolve_callbacks.push_back(nr);
1595 }
1596
1597
1598 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1599 {
1600         size_t len = m_pending_resolve_callbacks.size();
1601         for (size_t i = 0; i != len; i++) {
1602                 if (nr != m_pending_resolve_callbacks[i])
1603                         continue;
1604
1605                 len--;
1606                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1607                 m_pending_resolve_callbacks.resize(len);
1608                 return true;
1609         }
1610
1611         return false;
1612 }
1613
1614
1615 void CNodeDefManager::runNodeResolveCallbacks()
1616 {
1617         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1618                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1619                 nr->nodeResolveInternal();
1620         }
1621
1622         m_pending_resolve_callbacks.clear();
1623 }
1624
1625
1626 void CNodeDefManager::resetNodeResolveState()
1627 {
1628         m_node_registration_complete = false;
1629         m_pending_resolve_callbacks.clear();
1630 }
1631
1632 void CNodeDefManager::mapNodeboxConnections()
1633 {
1634         for (ContentFeatures &f : m_content_features) {
1635                 if (f.drawtype != NDT_NODEBOX || f.node_box.type != NODEBOX_CONNECTED)
1636                         continue;
1637
1638                 for (const std::string &name : f.connects_to) {
1639                         getIds(name, f.connects_to_ids);
1640                 }
1641         }
1642 }
1643
1644 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1645 {
1646         const ContentFeatures &f1 = get(from);
1647
1648         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1649                 return false;
1650
1651         // lookup target in connected set
1652         if (!CONTAINS(f1.connects_to_ids, to.param0))
1653                 return false;
1654
1655         const ContentFeatures &f2 = get(to);
1656
1657         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1658                 // ignores actually looking if back connection exists
1659                 return CONTAINS(f2.connects_to_ids, from.param0);
1660
1661         // does to node declare usable faces?
1662         if (f2.connect_sides > 0) {
1663                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1664                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1665                                 && (connect_face >= 4)) {
1666                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1667                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1668                                 0, // 4 - back
1669                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1670                                 0, // 8 - right
1671                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1672                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1673                                 0, // 16 - front
1674                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1675                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1676                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1677                                 };
1678                         return (f2.connect_sides
1679                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1680                 }
1681                 return (f2.connect_sides & connect_face);
1682         }
1683         // the target is just a regular node, so connect no matter back connection
1684         return true;
1685 }
1686
1687 ////
1688 //// NodeResolver
1689 ////
1690
1691 NodeResolver::NodeResolver()
1692 {
1693         m_nodenames.reserve(16);
1694         m_nnlistsizes.reserve(4);
1695 }
1696
1697
1698 NodeResolver::~NodeResolver()
1699 {
1700         if (!m_resolve_done && m_ndef)
1701                 m_ndef->cancelNodeResolveCallback(this);
1702 }
1703
1704
1705 void NodeResolver::nodeResolveInternal()
1706 {
1707         m_nodenames_idx   = 0;
1708         m_nnlistsizes_idx = 0;
1709
1710         resolveNodeNames();
1711         m_resolve_done = true;
1712
1713         m_nodenames.clear();
1714         m_nnlistsizes.clear();
1715 }
1716
1717
1718 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1719         const std::string &node_alt, content_t c_fallback)
1720 {
1721         if (m_nodenames_idx == m_nodenames.size()) {
1722                 *result_out = c_fallback;
1723                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1724                 return false;
1725         }
1726
1727         content_t c;
1728         std::string name = m_nodenames[m_nodenames_idx++];
1729
1730         bool success = m_ndef->getId(name, c);
1731         if (!success && !node_alt.empty()) {
1732                 name = node_alt;
1733                 success = m_ndef->getId(name, c);
1734         }
1735
1736         if (!success) {
1737                 errorstream << "NodeResolver: failed to resolve node name '" << name
1738                         << "'." << std::endl;
1739                 c = c_fallback;
1740         }
1741
1742         *result_out = c;
1743         return success;
1744 }
1745
1746
1747 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1748         bool all_required, content_t c_fallback)
1749 {
1750         bool success = true;
1751
1752         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1753                 errorstream << "NodeResolver: no more node lists" << std::endl;
1754                 return false;
1755         }
1756
1757         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1758
1759         while (length--) {
1760                 if (m_nodenames_idx == m_nodenames.size()) {
1761                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1762                         return false;
1763                 }
1764
1765                 content_t c;
1766                 std::string &name = m_nodenames[m_nodenames_idx++];
1767
1768                 if (name.substr(0,6) != "group:") {
1769                         if (m_ndef->getId(name, c)) {
1770                                 result_out->push_back(c);
1771                         } else if (all_required) {
1772                                 errorstream << "NodeResolver: failed to resolve node name '"
1773                                         << name << "'." << std::endl;
1774                                 result_out->push_back(c_fallback);
1775                                 success = false;
1776                         }
1777                 } else {
1778                         m_ndef->getIds(name, *result_out);
1779                 }
1780         }
1781
1782         return success;
1783 }