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