Allow ObjDefManager instances to be cloned
[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::vector<TextureOverride> &overrides)
1308 {
1309         infostream << "NodeDefManager::applyTextureOverrides(): Applying "
1310                 "overrides to textures" << std::endl;
1311
1312         for (const TextureOverride& texture_override : overrides) {
1313                 content_t id;
1314                 if (!getId(texture_override.id, id))
1315                         continue; // Ignore unknown node
1316
1317                 ContentFeatures &nodedef = m_content_features[id];
1318
1319                 if (texture_override.hasTarget(OverrideTarget::TOP))
1320                         nodedef.tiledef[0].name = texture_override.texture;
1321
1322                 if (texture_override.hasTarget(OverrideTarget::BOTTOM))
1323                         nodedef.tiledef[1].name = texture_override.texture;
1324
1325                 if (texture_override.hasTarget(OverrideTarget::RIGHT))
1326                         nodedef.tiledef[2].name = texture_override.texture;
1327
1328                 if (texture_override.hasTarget(OverrideTarget::LEFT))
1329                         nodedef.tiledef[3].name = texture_override.texture;
1330
1331                 if (texture_override.hasTarget(OverrideTarget::BACK))
1332                         nodedef.tiledef[4].name = texture_override.texture;
1333
1334                 if (texture_override.hasTarget(OverrideTarget::FRONT))
1335                         nodedef.tiledef[5].name = texture_override.texture;
1336         }
1337 }
1338
1339 void NodeDefManager::updateTextures(IGameDef *gamedef,
1340         void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1341         void *progress_callback_args)
1342 {
1343 #ifndef SERVER
1344         infostream << "NodeDefManager::updateTextures(): Updating "
1345                 "textures in node definitions" << std::endl;
1346
1347         Client *client = (Client *)gamedef;
1348         ITextureSource *tsrc = client->tsrc();
1349         IShaderSource *shdsrc = client->getShaderSource();
1350         scene::IMeshManipulator *meshmanip =
1351                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1352         TextureSettings tsettings;
1353         tsettings.readSettings();
1354
1355         u32 size = m_content_features.size();
1356
1357         for (u32 i = 0; i < size; i++) {
1358                 ContentFeatures *f = &(m_content_features[i]);
1359                 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1360                 progress_callback(progress_callback_args, i, size);
1361         }
1362 #endif
1363 }
1364
1365 void NodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1366 {
1367         writeU8(os, 1); // version
1368         u16 count = 0;
1369         std::ostringstream os2(std::ios::binary);
1370         for (u32 i = 0; i < m_content_features.size(); i++) {
1371                 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1372                                 || i == CONTENT_UNKNOWN)
1373                         continue;
1374                 const ContentFeatures *f = &m_content_features[i];
1375                 if (f->name.empty())
1376                         continue;
1377                 writeU16(os2, i);
1378                 // Wrap it in a string to allow different lengths without
1379                 // strict version incompatibilities
1380                 std::ostringstream wrapper_os(std::ios::binary);
1381                 f->serialize(wrapper_os, protocol_version);
1382                 os2<<serializeString(wrapper_os.str());
1383
1384                 // must not overflow
1385                 u16 next = count + 1;
1386                 FATAL_ERROR_IF(next < count, "Overflow");
1387                 count++;
1388         }
1389         writeU16(os, count);
1390         os << serializeLongString(os2.str());
1391 }
1392
1393
1394 void NodeDefManager::deSerialize(std::istream &is)
1395 {
1396         clear();
1397         int version = readU8(is);
1398         if (version != 1)
1399                 throw SerializationError("unsupported NodeDefinitionManager version");
1400         u16 count = readU16(is);
1401         std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1402         ContentFeatures f;
1403         for (u16 n = 0; n < count; n++) {
1404                 u16 i = readU16(is2);
1405
1406                 // Read it from the string wrapper
1407                 std::string wrapper = deSerializeString(is2);
1408                 std::istringstream wrapper_is(wrapper, std::ios::binary);
1409                 f.deSerialize(wrapper_is);
1410
1411                 // Check error conditions
1412                 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1413                         warningstream << "NodeDefManager::deSerialize(): "
1414                                 "not changing builtin node " << i << std::endl;
1415                         continue;
1416                 }
1417                 if (f.name.empty()) {
1418                         warningstream << "NodeDefManager::deSerialize(): "
1419                                 "received empty name" << std::endl;
1420                         continue;
1421                 }
1422
1423                 // Ignore aliases
1424                 u16 existing_id;
1425                 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1426                         warningstream << "NodeDefManager::deSerialize(): "
1427                                 "already defined with different ID: " << f.name << std::endl;
1428                         continue;
1429                 }
1430
1431                 // All is ok, add node definition with the requested ID
1432                 if (i >= m_content_features.size())
1433                         m_content_features.resize((u32)(i) + 1);
1434                 m_content_features[i] = f;
1435                 addNameIdMapping(i, f.name);
1436                 TRACESTREAM(<< "NodeDef: deserialized " << f.name << std::endl);
1437
1438                 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1439                 fixSelectionBoxIntUnion();
1440         }
1441 }
1442
1443
1444 void NodeDefManager::addNameIdMapping(content_t i, std::string name)
1445 {
1446         m_name_id_mapping.set(i, name);
1447         m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1448 }
1449
1450
1451 NodeDefManager *createNodeDefManager()
1452 {
1453         return new NodeDefManager();
1454 }
1455
1456
1457 void NodeDefManager::pendNodeResolve(NodeResolver *nr) const
1458 {
1459         nr->m_ndef = this;
1460         if (m_node_registration_complete)
1461                 nr->nodeResolveInternal();
1462         else
1463                 m_pending_resolve_callbacks.push_back(nr);
1464 }
1465
1466
1467 bool NodeDefManager::cancelNodeResolveCallback(NodeResolver *nr) const
1468 {
1469         size_t len = m_pending_resolve_callbacks.size();
1470         for (size_t i = 0; i != len; i++) {
1471                 if (nr != m_pending_resolve_callbacks[i])
1472                         continue;
1473
1474                 len--;
1475                 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1476                 m_pending_resolve_callbacks.resize(len);
1477                 return true;
1478         }
1479
1480         return false;
1481 }
1482
1483
1484 void NodeDefManager::runNodeResolveCallbacks()
1485 {
1486         for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1487                 NodeResolver *nr = m_pending_resolve_callbacks[i];
1488                 nr->nodeResolveInternal();
1489         }
1490
1491         m_pending_resolve_callbacks.clear();
1492 }
1493
1494
1495 void NodeDefManager::resetNodeResolveState()
1496 {
1497         m_node_registration_complete = false;
1498         m_pending_resolve_callbacks.clear();
1499 }
1500
1501 void NodeDefManager::mapNodeboxConnections()
1502 {
1503         for (ContentFeatures &f : m_content_features) {
1504                 if (f.drawtype != NDT_NODEBOX || f.node_box.type != NODEBOX_CONNECTED)
1505                         continue;
1506
1507                 for (const std::string &name : f.connects_to) {
1508                         getIds(name, f.connects_to_ids);
1509                 }
1510         }
1511 }
1512
1513 bool NodeDefManager::nodeboxConnects(MapNode from, MapNode to,
1514         u8 connect_face) const
1515 {
1516         const ContentFeatures &f1 = get(from);
1517
1518         if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1519                 return false;
1520
1521         // lookup target in connected set
1522         if (!CONTAINS(f1.connects_to_ids, to.param0))
1523                 return false;
1524
1525         const ContentFeatures &f2 = get(to);
1526
1527         if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1528                 // ignores actually looking if back connection exists
1529                 return CONTAINS(f2.connects_to_ids, from.param0);
1530
1531         // does to node declare usable faces?
1532         if (f2.connect_sides > 0) {
1533                 if ((f2.param_type_2 == CPT2_FACEDIR ||
1534                                 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1535                                 && (connect_face >= 4)) {
1536                         static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1537                                 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1538                                 0, // 4 - back
1539                                 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1540                                 0, // 8 - right
1541                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1542                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1543                                 0, // 16 - front
1544                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1545                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1546                                 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1547                                 };
1548                         return (f2.connect_sides
1549                                 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1550                 }
1551                 return (f2.connect_sides & connect_face);
1552         }
1553         // the target is just a regular node, so connect no matter back connection
1554         return true;
1555 }
1556
1557 ////
1558 //// NodeResolver
1559 ////
1560
1561 NodeResolver::NodeResolver()
1562 {
1563         m_nodenames.reserve(16);
1564         m_nnlistsizes.reserve(4);
1565 }
1566
1567
1568 NodeResolver::~NodeResolver()
1569 {
1570         if (!m_resolve_done && m_ndef)
1571                 m_ndef->cancelNodeResolveCallback(this);
1572 }
1573
1574
1575 void NodeResolver::cloneTo(NodeResolver *res) const
1576 {
1577         FATAL_ERROR_IF(!m_resolve_done, "NodeResolver can only be cloned"
1578                 " after resolving has completed");
1579         /* We don't actually do anything significant. Since the node resolving has
1580          * already completed, the class that called us will already have the
1581          * resolved IDs in its data structures (which it copies on its own) */
1582         res->m_ndef = m_ndef;
1583         res->m_resolve_done = true;
1584 }
1585
1586
1587 void NodeResolver::nodeResolveInternal()
1588 {
1589         m_nodenames_idx   = 0;
1590         m_nnlistsizes_idx = 0;
1591
1592         resolveNodeNames();
1593         m_resolve_done = true;
1594
1595         m_nodenames.clear();
1596         m_nnlistsizes.clear();
1597 }
1598
1599
1600 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1601         const std::string &node_alt, content_t c_fallback, bool error_on_fallback)
1602 {
1603         if (m_nodenames_idx == m_nodenames.size()) {
1604                 *result_out = c_fallback;
1605                 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1606                 return false;
1607         }
1608
1609         content_t c;
1610         std::string name = m_nodenames[m_nodenames_idx++];
1611
1612         bool success = m_ndef->getId(name, c);
1613         if (!success && !node_alt.empty()) {
1614                 name = node_alt;
1615                 success = m_ndef->getId(name, c);
1616         }
1617
1618         if (!success) {
1619                 if (error_on_fallback)
1620                         errorstream << "NodeResolver: failed to resolve node name '" << name
1621                                 << "'." << std::endl;
1622                 c = c_fallback;
1623         }
1624
1625         *result_out = c;
1626         return success;
1627 }
1628
1629
1630 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1631         bool all_required, content_t c_fallback)
1632 {
1633         bool success = true;
1634
1635         if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1636                 errorstream << "NodeResolver: no more node lists" << std::endl;
1637                 return false;
1638         }
1639
1640         size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1641
1642         while (length--) {
1643                 if (m_nodenames_idx == m_nodenames.size()) {
1644                         errorstream << "NodeResolver: no more nodes in list" << std::endl;
1645                         return false;
1646                 }
1647
1648                 content_t c;
1649                 std::string &name = m_nodenames[m_nodenames_idx++];
1650
1651                 if (name.substr(0,6) != "group:") {
1652                         if (m_ndef->getId(name, c)) {
1653                                 result_out->push_back(c);
1654                         } else if (all_required) {
1655                                 errorstream << "NodeResolver: failed to resolve node name '"
1656                                         << name << "'." << std::endl;
1657                                 result_out->push_back(c_fallback);
1658                                 success = false;
1659                         }
1660                 } else {
1661                         m_ndef->getIds(name, *result_out);
1662                 }
1663         }
1664
1665         return success;
1666 }