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