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