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