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