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