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