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