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