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