3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
26 #include "client/renderingengine.h"
27 #include "client/tile.h"
28 #include <IMeshManipulator.h>
32 #include "nameidmapping.h"
33 #include "util/numeric.h"
34 #include "util/serialize.h"
35 #include "exceptions.h"
39 #include <fstream> // Used in applyTextureOverrides()
47 type = NODEBOX_REGULAR;
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
56 connect_bottom.clear();
57 connect_front.clear();
60 connect_right.clear();
63 void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
67 if (protocol_version >= 27)
75 writeU8(os, NODEBOX_FIXED);
79 writeU16(os, fixed.size());
80 for (std::vector<aabb3f>::const_iterator
82 i != fixed.end(); ++i)
84 writeV3F1000(os, i->MinEdge);
85 writeV3F1000(os, i->MaxEdge);
88 case NODEBOX_WALLMOUNTED:
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);
98 case NODEBOX_CONNECTED:
100 // send old clients nodes that can't be walked through
102 writeU8(os, NODEBOX_FIXED);
105 writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2));
106 writeV3F1000(os, v3f(BS/2, BS/2, BS/2));
110 #define WRITEBOX(box) do { \
111 writeU16(os, (box).size()); \
112 for (std::vector<aabb3f>::const_iterator \
114 i != (box).end(); ++i) { \
115 writeV3F1000(os, i->MinEdge); \
116 writeV3F1000(os, i->MaxEdge); \
120 WRITEBOX(connect_top);
121 WRITEBOX(connect_bottom);
122 WRITEBOX(connect_front);
123 WRITEBOX(connect_left);
124 WRITEBOX(connect_back);
125 WRITEBOX(connect_right);
134 void NodeBox::deSerialize(std::istream &is)
136 int version = readU8(is);
137 if (version < 1 || version > 3)
138 throw SerializationError("unsupported NodeBox version");
142 type = (enum NodeBoxType)readU8(is);
144 if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
146 u16 fixed_count = readU16(is);
150 box.MinEdge = readV3F1000(is);
151 box.MaxEdge = readV3F1000(is);
152 fixed.push_back(box);
155 else if(type == NODEBOX_WALLMOUNTED)
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);
164 else if (type == NODEBOX_CONNECTED)
166 #define READBOXES(box) do { \
167 count = readU16(is); \
168 (box).reserve(count); \
170 v3f min = readV3F1000(is); \
171 v3f max = readV3F1000(is); \
172 (box).push_back(aabb3f(min, max)); }; } while (0)
177 READBOXES(connect_top);
178 READBOXES(connect_bottom);
179 READBOXES(connect_front);
180 READBOXES(connect_left);
181 READBOXES(connect_back);
182 READBOXES(connect_right);
190 void TileDef::serialize(std::ostream &os, u16 protocol_version) const
192 if (protocol_version >= 30)
194 else if (protocol_version >= 29)
196 else if (protocol_version >= 26)
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);
208 if (protocol_version >= 30) {
209 writeU8(os, has_color);
211 writeU8(os, color.getRed());
212 writeU8(os, color.getGreen());
213 writeU8(os, color.getBlue());
218 void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
220 int version = readU8(is);
221 name = deSerializeString(is);
222 animation.deSerialize(is, version >= 3 ? 29 : 26);
224 backface_culling = readU8(is);
226 tileable_horizontal = readU8(is);
227 tileable_vertical = readU8(is);
230 has_color = readU8(is);
232 color.setRed(readU8(is));
233 color.setGreen(readU8(is));
234 color.setBlue(readU8(is));
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;
248 SimpleSoundSpec serialization
251 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
252 std::ostream &os, u8 version)
254 os<<serializeString(ss.name);
255 writeF1000(os, ss.gain);
258 writeF1000(os, ss.pitch);
260 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is, u8 version)
262 ss.name = deSerializeString(is);
263 ss.gain = readF1000(is);
266 ss.pitch = readF1000(is);
269 void TextureSettings::readSettings()
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");
281 // Mesh cache is not supported in combination with smooth lighting
283 enable_mesh_cache = false;
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;
292 leaves_style = LEAVES_OPAQUE;
300 ContentFeatures::ContentFeatures()
305 ContentFeatures::~ContentFeatures()
309 void ContentFeatures::reset()
316 visual_solidness = 0;
317 backface_culling = true;
320 has_on_construct = false;
321 has_on_destruct = false;
322 has_after_destruct = false;
326 NOTE: Most of this is always overridden by the default values given
331 // Unknown nodes can be dug
332 groups["dig_immediate"] = 2;
333 drawtype = NDT_NORMAL;
336 for(u32 i = 0; i < 24; i++)
338 minimap_color = video::SColor(0, 0, 0, 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();
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;
356 buildable_to = false;
358 rightclickable = true;
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;
368 damage_per_second = 0;
369 node_box = NodeBox();
370 selection_box = NodeBox();
371 collision_box = NodeBox();
373 legacy_facedir_simple = false;
374 legacy_wallmounted = false;
375 sound_footstep = SimpleSoundSpec();
376 sound_dig = SimpleSoundSpec("__group");
377 sound_dug = SimpleSoundSpec();
379 connects_to_ids.clear();
381 color = video::SColor(0xFFFFFFFF);
386 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
388 if (protocol_version < 31) {
389 serializeOld(os, protocol_version);
394 u8 version = (protocol_version >= 34) ? 11 : 10;
395 writeU8(os, version);
398 os << serializeString(name);
399 writeU16(os, groups.size());
400 for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
402 os << serializeString(i->first);
403 writeS16(os, i->second);
405 writeU8(os, param_type);
406 writeU8(os, param_type_2);
409 writeU8(os, drawtype);
410 os << serializeString(mesh);
411 writeF1000(os, visual_scale);
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);
422 writeU8(os, color.getRed());
423 writeU8(os, color.getGreen());
424 writeU8(os, color.getBlue());
425 os << serializeString(palette_name);
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)
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);
439 writeU8(os, light_propagates);
440 writeU8(os, sunlight_propagates);
441 writeU8(os, light_source);
444 writeU8(os, is_ground_content);
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);
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);
466 node_box.serialize(os, protocol_version);
467 selection_box.serialize(os, protocol_version);
468 collision_box.serialize(os, protocol_version);
471 serializeSimpleSoundSpec(sound_footstep, os, version);
472 serializeSimpleSoundSpec(sound_dig, os, version);
473 serializeSimpleSoundSpec(sound_dug, os, version);
476 writeU8(os, legacy_facedir_simple);
477 writeU8(os, legacy_wallmounted);
480 void ContentFeatures::correctAlpha(TileDef *tiles, int length)
482 // alpha == 0 means that the node is using texture alpha
483 if (alpha == 0 || alpha == 255)
486 for (int i = 0; i < length; i++) {
487 if (tiles[i].name == "")
490 s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha);
491 tiles[i].name = s.str();
495 void ContentFeatures::deSerialize(std::istream &is)
498 int version = readU8(is);
500 deSerializeOld(is, version);
502 } else if (version > 11) {
503 throw SerializationError("unsupported ContentFeatures version");
507 name = deSerializeString(is);
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;
515 param_type = (enum ContentParamType) readU8(is);
516 param_type_2 = (enum ContentParamType2) readU8(is);
519 drawtype = (enum NodeDrawType) readU8(is);
520 mesh = deSerializeString(is);
521 visual_scale = readF1000(is);
523 throw SerializationError("unsupported tile count");
524 for (u32 i = 0; i < 6; i++)
525 tiledef[i].deSerialize(is, version, drawtype);
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);
534 color.setRed(readU8(is));
535 color.setGreen(readU8(is));
536 color.setBlue(readU8(is));
537 palette_name = deSerializeString(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);
551 light_propagates = readU8(is);
552 sunlight_propagates = readU8(is);
553 light_source = readU8(is);
554 light_source = MYMIN(light_source, LIGHT_MAX);
557 is_ground_content = readU8(is);
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);
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);
579 node_box.deSerialize(is);
580 selection_box.deSerialize(is);
581 collision_box.deSerialize(is);
584 deSerializeSimpleSoundSpec(sound_footstep, is, version);
585 deSerializeSimpleSoundSpec(sound_dig, is, version);
586 deSerializeSimpleSoundSpec(sound_dug, is, version);
588 // read legacy properties
589 legacy_facedir_simple = readU8(is);
590 legacy_wallmounted = readU8(is);
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)
598 tile->shader_id = shader_id;
599 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
600 tile->material_type = material_type;
602 // Normal texture and shader flags texture
603 if (use_normal_texture) {
604 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
606 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
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;
620 tile->has_color = tiledef->has_color;
621 if (tiledef->has_color)
622 tile->color = tiledef->color;
626 // Animation parameters
628 if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
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;
636 if (frame_count == 1) {
637 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
639 std::ostringstream os(std::ios::binary);
640 tile->frames.resize(frame_count);
642 for (int i = 0; i < frame_count; i++) {
648 tiledef->animation.getTextureModifer(os,
649 tile->texture->getOriginalSize(), i);
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;
662 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
663 scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
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);
669 // Figure out the actual tiles to use
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";
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];
685 bool is_liquid = false;
687 u8 material_type = (alpha == 255) ?
688 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
699 assert(liquid_type == LIQUID_SOURCE);
700 if (tsettings.opaque_water)
705 case NDT_FLOWINGLIQUID:
706 assert(liquid_type == LIQUID_FLOWING);
708 if (tsettings.opaque_water)
714 visual_solidness = 1;
716 case NDT_GLASSLIKE_FRAMED:
718 visual_solidness = 1;
720 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
722 visual_solidness = 1;
723 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
727 visual_solidness = 1;
729 case NDT_ALLFACES_OPTIONAL:
730 if (tsettings.leaves_style == LEAVES_FANCY) {
731 drawtype = NDT_ALLFACES;
733 visual_solidness = 1;
734 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
735 for (u32 j = 0; j < 6; j++) {
736 if (tdef_spec[j].name != "")
737 tdef[j].name = tdef_spec[j].name;
739 drawtype = NDT_GLASSLIKE;
741 visual_solidness = 1;
743 drawtype = NDT_NORMAL;
745 for (u32 i = 0; i < 6; i++)
746 tdef[i].name += std::string("^[noalpha");
749 material_type = TILE_MATERIAL_WAVING_LEAVES;
754 material_type = TILE_MATERIAL_WAVING_PLANTS;
763 material_type = TILE_MATERIAL_WAVING_PLANTS;
764 else if (waving == 2)
765 material_type = TILE_MATERIAL_WAVING_LEAVES;
776 // Vertex alpha is no longer supported, correct if necessary.
777 correctAlpha(tdef, 6);
778 correctAlpha(tdef_overlay, 6);
779 correctAlpha(tdef_spec, CF_SPECIAL_COUNT);
780 material_type = (alpha == 255) ?
781 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
785 for (u16 j = 0; j < 6; j++) {
786 tile_shader[j] = shdsrc->getShader("nodes_shader",
787 material_type, drawtype);
790 // Tiles (fill in f->tiles[])
791 for (u16 j = 0; j < 6; j++) {
792 fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
793 tsettings.use_normal_texture,
794 tdef[j].backface_culling, material_type);
795 if (tdef_overlay[j].name != "")
796 fillTileAttribs(tsrc, &tiles[j].layers[1], &tdef_overlay[j],
797 tile_shader[j], tsettings.use_normal_texture,
798 tdef[j].backface_culling, material_type);
801 // Special tiles (fill in f->special_tiles[])
802 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
803 fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tdef_spec[j],
804 tile_shader[j], tsettings.use_normal_texture,
805 tdef_spec[j].backface_culling, material_type);
808 if (param_type_2 == CPT2_COLOR ||
809 param_type_2 == CPT2_COLORED_FACEDIR ||
810 param_type_2 == CPT2_COLORED_WALLMOUNTED)
811 palette = tsrc->getPalette(palette_name);
813 if ((drawtype == NDT_MESH) && (mesh != "")) {
815 // Read the mesh and apply scale
816 mesh_ptr[0] = client->getMesh(mesh);
818 v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
819 scaleMesh(mesh_ptr[0], scale);
820 recalculateBoundingBox(mesh_ptr[0]);
821 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
823 } else if ((drawtype == NDT_NODEBOX) &&
824 ((node_box.type == NODEBOX_REGULAR) ||
825 (node_box.type == NODEBOX_FIXED)) &&
826 (!node_box.fixed.empty())) {
827 //Convert regular nodebox nodes to meshnodes
828 //Change the drawtype and apply scale
830 mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
831 v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
832 scaleMesh(mesh_ptr[0], scale);
833 recalculateBoundingBox(mesh_ptr[0]);
834 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
837 //Cache 6dfacedir and wallmounted rotated clones of meshes
838 if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
839 (param_type_2 == CPT2_FACEDIR
840 || param_type_2 == CPT2_COLORED_FACEDIR)) {
841 for (u16 j = 1; j < 24; j++) {
842 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
843 rotateMeshBy6dFacedir(mesh_ptr[j], j);
844 recalculateBoundingBox(mesh_ptr[j]);
845 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
847 } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
848 && (param_type_2 == CPT2_WALLMOUNTED ||
849 param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
850 static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
851 for (u16 j = 1; j < 6; j++) {
852 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
853 rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
854 recalculateBoundingBox(mesh_ptr[j]);
855 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
857 rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
858 recalculateBoundingBox(mesh_ptr[0]);
859 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
868 class CNodeDefManager: public IWritableNodeDefManager {
871 virtual ~CNodeDefManager();
873 virtual IWritableNodeDefManager *clone();
874 inline virtual const ContentFeatures& get(content_t c) const;
875 inline virtual const ContentFeatures& get(const MapNode &n) const;
876 virtual bool getId(const std::string &name, content_t &result) const;
877 virtual content_t getId(const std::string &name) const;
878 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
879 virtual const ContentFeatures& get(const std::string &name) const;
880 content_t allocateId();
881 virtual content_t set(const std::string &name, const ContentFeatures &def);
882 virtual content_t allocateDummy(const std::string &name);
883 virtual void removeNode(const std::string &name);
884 virtual void updateAliases(IItemDefManager *idef);
885 virtual void applyTextureOverrides(const std::string &override_filepath);
886 virtual void updateTextures(IGameDef *gamedef,
887 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
888 void *progress_cbk_args);
889 void serialize(std::ostream &os, u16 protocol_version) const;
890 void deSerialize(std::istream &is);
892 inline virtual void setNodeRegistrationStatus(bool completed);
894 virtual void pendNodeResolve(NodeResolver *nr);
895 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
896 virtual void runNodeResolveCallbacks();
897 virtual void resetNodeResolveState();
898 virtual void mapNodeboxConnections();
899 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
900 virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
902 return m_selection_box_int_union;
906 void addNameIdMapping(content_t i, std::string name);
908 * Recalculates m_selection_box_int_union based on
909 * m_selection_box_union.
911 void fixSelectionBoxIntUnion();
913 // Features indexed by id
914 std::vector<ContentFeatures> m_content_features;
916 // A mapping for fast converting back and forth between names and ids
917 NameIdMapping m_name_id_mapping;
919 // Like m_name_id_mapping, but only from names to ids, and includes
920 // item aliases too. Updated by updateAliases()
921 // Note: Not serialized.
923 std::unordered_map<std::string, content_t> m_name_id_mapping_with_aliases;
925 // A mapping from groups to a list of content_ts (and their levels)
926 // that belong to it. Necessary for a direct lookup in getIds().
927 // Note: Not serialized.
928 std::unordered_map<std::string, GroupItems> m_group_to_items;
930 // Next possibly free id
933 // NodeResolvers to callback once node registration has ended
934 std::vector<NodeResolver *> m_pending_resolve_callbacks;
936 // True when all nodes have been registered
937 bool m_node_registration_complete;
939 //! The union of all nodes' selection boxes.
940 aabb3f m_selection_box_union;
942 * The smallest box in node coordinates that
943 * contains all nodes' selection boxes.
945 core::aabbox3d<s16> m_selection_box_int_union;
949 CNodeDefManager::CNodeDefManager()
955 CNodeDefManager::~CNodeDefManager()
958 for (u32 i = 0; i < m_content_features.size(); i++) {
959 ContentFeatures *f = &m_content_features[i];
960 for (u32 j = 0; j < 24; j++) {
962 f->mesh_ptr[j]->drop();
969 void CNodeDefManager::clear()
971 m_content_features.clear();
972 m_name_id_mapping.clear();
973 m_name_id_mapping_with_aliases.clear();
974 m_group_to_items.clear();
976 m_selection_box_union.reset(0,0,0);
977 m_selection_box_int_union.reset(0,0,0);
979 resetNodeResolveState();
981 u32 initial_length = 0;
982 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
983 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
984 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
985 m_content_features.resize(initial_length);
987 // Set CONTENT_UNKNOWN
991 // Insert directly into containers
992 content_t c = CONTENT_UNKNOWN;
993 m_content_features[c] = f;
994 addNameIdMapping(c, f.name);
1001 f.drawtype = NDT_AIRLIKE;
1002 f.param_type = CPT_LIGHT;
1003 f.light_propagates = true;
1004 f.sunlight_propagates = true;
1006 f.pointable = false;
1008 f.buildable_to = true;
1010 f.is_ground_content = true;
1011 // Insert directly into containers
1012 content_t c = CONTENT_AIR;
1013 m_content_features[c] = f;
1014 addNameIdMapping(c, f.name);
1017 // Set CONTENT_IGNORE
1021 f.drawtype = NDT_AIRLIKE;
1022 f.param_type = CPT_NONE;
1023 f.light_propagates = false;
1024 f.sunlight_propagates = false;
1026 f.pointable = false;
1028 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
1029 f.is_ground_content = true;
1030 // Insert directly into containers
1031 content_t c = CONTENT_IGNORE;
1032 m_content_features[c] = f;
1033 addNameIdMapping(c, f.name);
1038 IWritableNodeDefManager *CNodeDefManager::clone()
1040 CNodeDefManager *mgr = new CNodeDefManager();
1046 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1048 return c < m_content_features.size()
1049 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1053 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1055 return get(n.getContent());
1059 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1061 std::unordered_map<std::string, content_t>::const_iterator
1062 i = m_name_id_mapping_with_aliases.find(name);
1063 if(i == m_name_id_mapping_with_aliases.end())
1070 content_t CNodeDefManager::getId(const std::string &name) const
1072 content_t id = CONTENT_IGNORE;
1078 bool CNodeDefManager::getIds(const std::string &name,
1079 std::set<content_t> &result) const
1081 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1082 if (name.substr(0,6) != "group:") {
1083 content_t id = CONTENT_IGNORE;
1084 bool exists = getId(name, id);
1089 std::string group = name.substr(6);
1091 std::unordered_map<std::string, GroupItems>::const_iterator
1092 i = m_group_to_items.find(group);
1093 if (i == m_group_to_items.end())
1096 const GroupItems &items = i->second;
1097 for (GroupItems::const_iterator j = items.begin();
1098 j != items.end(); ++j) {
1099 if ((*j).second != 0)
1100 result.insert((*j).first);
1102 //printf("getIds: %dus\n", t.stop());
1107 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1109 content_t id = CONTENT_UNKNOWN;
1115 // returns CONTENT_IGNORE if no free ID found
1116 content_t CNodeDefManager::allocateId()
1118 for (content_t id = m_next_id;
1119 id >= m_next_id; // overflow?
1121 while (id >= m_content_features.size()) {
1122 m_content_features.push_back(ContentFeatures());
1124 const ContentFeatures &f = m_content_features[id];
1130 // If we arrive here, an overflow occurred in id.
1131 // That means no ID was found
1132 return CONTENT_IGNORE;
1137 * Returns the smallest box that contains all boxes
1138 * in the vector. Box_union is expanded.
1139 * @param[in] boxes the vector containing the boxes
1140 * @param[in, out] box_union the union of the arguments
1142 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1144 for (std::vector<aabb3f>::const_iterator it = boxes.begin();
1145 it != boxes.end(); ++it) {
1146 box_union->addInternalBox(*it);
1152 * Returns a box that contains the nodebox in every case.
1153 * The argument node_union is expanded.
1154 * @param[in] nodebox the nodebox to be measured
1155 * @param[in] features used to decide whether the nodebox
1157 * @param[in, out] box_union the union of the arguments
1159 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1162 switch(nodebox.type) {
1164 case NODEBOX_LEVELED: {
1166 aabb3f half_processed(0, 0, 0, 0, 0, 0);
1167 boxVectorUnion(nodebox.fixed, &half_processed);
1168 // Set leveled boxes to maximal
1169 if (nodebox.type == NODEBOX_LEVELED) {
1170 half_processed.MaxEdge.Y = +BS / 2;
1172 if (features.param_type_2 == CPT2_FACEDIR ||
1173 features.param_type_2 == CPT2_COLORED_FACEDIR) {
1174 // Get maximal coordinate
1176 fabsf(half_processed.MinEdge.X),
1177 fabsf(half_processed.MinEdge.Y),
1178 fabsf(half_processed.MinEdge.Z),
1179 fabsf(half_processed.MaxEdge.X),
1180 fabsf(half_processed.MaxEdge.Y),
1181 fabsf(half_processed.MaxEdge.Z) };
1183 for (int i = 0; i < 6; i++) {
1184 if (max < coords[i]) {
1188 // Add the union of all possible rotated boxes
1189 box_union->addInternalPoint(-max, -max, -max);
1190 box_union->addInternalPoint(+max, +max, +max);
1192 box_union->addInternalBox(half_processed);
1196 case NODEBOX_WALLMOUNTED: {
1198 box_union->addInternalBox(nodebox.wall_top);
1199 box_union->addInternalBox(nodebox.wall_bottom);
1200 // Find maximal coordinate in the X-Z plane
1202 fabsf(nodebox.wall_side.MinEdge.X),
1203 fabsf(nodebox.wall_side.MinEdge.Z),
1204 fabsf(nodebox.wall_side.MaxEdge.X),
1205 fabsf(nodebox.wall_side.MaxEdge.Z) };
1207 for (int i = 0; i < 4; i++) {
1208 if (max < coords[i]) {
1212 // Add the union of all possible rotated boxes
1213 box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1214 box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1217 case NODEBOX_CONNECTED: {
1218 // Add all possible connected boxes
1219 boxVectorUnion(nodebox.fixed, box_union);
1220 boxVectorUnion(nodebox.connect_top, box_union);
1221 boxVectorUnion(nodebox.connect_bottom, box_union);
1222 boxVectorUnion(nodebox.connect_front, box_union);
1223 boxVectorUnion(nodebox.connect_left, box_union);
1224 boxVectorUnion(nodebox.connect_back, box_union);
1225 boxVectorUnion(nodebox.connect_right, box_union);
1230 box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1231 box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1237 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1239 m_selection_box_int_union.MinEdge.X = floorf(
1240 m_selection_box_union.MinEdge.X / BS + 0.5f);
1241 m_selection_box_int_union.MinEdge.Y = floorf(
1242 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1243 m_selection_box_int_union.MinEdge.Z = floorf(
1244 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1245 m_selection_box_int_union.MaxEdge.X = ceilf(
1246 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1247 m_selection_box_int_union.MaxEdge.Y = ceilf(
1248 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1249 m_selection_box_int_union.MaxEdge.Z = ceilf(
1250 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1254 // IWritableNodeDefManager
1255 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1259 assert(name == def.name);
1261 // Don't allow redefining ignore (but allow air and unknown)
1262 if (name == "ignore") {
1263 warningstream << "NodeDefManager: Ignoring "
1264 "CONTENT_IGNORE redefinition"<<std::endl;
1265 return CONTENT_IGNORE;
1268 content_t id = CONTENT_IGNORE;
1269 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1272 if (id == CONTENT_IGNORE) {
1273 warningstream << "NodeDefManager: Absolute "
1274 "limit reached" << std::endl;
1275 return CONTENT_IGNORE;
1277 assert(id != CONTENT_IGNORE);
1278 addNameIdMapping(id, name);
1280 m_content_features[id] = def;
1281 verbosestream << "NodeDefManager: registering content id \"" << id
1282 << "\": name=\"" << def.name << "\""<<std::endl;
1284 getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1285 fixSelectionBoxIntUnion();
1286 // Add this content to the list of all groups it belongs to
1287 // FIXME: This should remove a node from groups it no longer
1288 // belongs to when a node is re-registered
1289 for (ItemGroupList::const_iterator i = def.groups.begin();
1290 i != def.groups.end(); ++i) {
1291 std::string group_name = i->first;
1293 std::unordered_map<std::string, GroupItems>::iterator
1294 j = m_group_to_items.find(group_name);
1295 if (j == m_group_to_items.end()) {
1296 m_group_to_items[group_name].push_back(
1297 std::make_pair(id, i->second));
1299 GroupItems &items = j->second;
1300 items.push_back(std::make_pair(id, i->second));
1307 content_t CNodeDefManager::allocateDummy(const std::string &name)
1309 assert(name != ""); // Pre-condition
1312 return set(name, f);
1316 void CNodeDefManager::removeNode(const std::string &name)
1321 // Erase name from name ID mapping
1322 content_t id = CONTENT_IGNORE;
1323 if (m_name_id_mapping.getId(name, id)) {
1324 m_name_id_mapping.eraseName(name);
1325 m_name_id_mapping_with_aliases.erase(name);
1328 // Erase node content from all groups it belongs to
1329 for (std::unordered_map<std::string, GroupItems>::iterator iter_groups =
1330 m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1331 GroupItems &items = iter_groups->second;
1332 for (GroupItems::iterator iter_groupitems = items.begin();
1333 iter_groupitems != items.end();) {
1334 if (iter_groupitems->first == id)
1335 items.erase(iter_groupitems++);
1340 // Check if group is empty
1341 if (items.size() == 0)
1342 m_group_to_items.erase(iter_groups++);
1349 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1351 std::set<std::string> all;
1353 m_name_id_mapping_with_aliases.clear();
1354 for (std::set<std::string>::const_iterator
1355 i = all.begin(); i != all.end(); ++i) {
1356 const std::string &name = *i;
1357 const std::string &convert_to = idef->getAlias(name);
1359 if (m_name_id_mapping.getId(convert_to, id)) {
1360 m_name_id_mapping_with_aliases.insert(
1361 std::make_pair(name, id));
1366 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1368 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1369 "overrides to textures from " << override_filepath << std::endl;
1371 std::ifstream infile(override_filepath.c_str());
1374 while (std::getline(infile, line)) {
1376 if (trim(line) == "")
1378 std::vector<std::string> splitted = str_split(line, ' ');
1379 if (splitted.size() != 3) {
1380 errorstream << override_filepath
1381 << ":" << line_c << " Could not apply texture override \""
1382 << line << "\": Syntax error" << std::endl;
1387 if (!getId(splitted[0], id))
1388 continue; // Ignore unknown node
1390 ContentFeatures &nodedef = m_content_features[id];
1392 if (splitted[1] == "top")
1393 nodedef.tiledef[0].name = splitted[2];
1394 else if (splitted[1] == "bottom")
1395 nodedef.tiledef[1].name = splitted[2];
1396 else if (splitted[1] == "right")
1397 nodedef.tiledef[2].name = splitted[2];
1398 else if (splitted[1] == "left")
1399 nodedef.tiledef[3].name = splitted[2];
1400 else if (splitted[1] == "back")
1401 nodedef.tiledef[4].name = splitted[2];
1402 else if (splitted[1] == "front")
1403 nodedef.tiledef[5].name = splitted[2];
1404 else if (splitted[1] == "all" || splitted[1] == "*")
1405 for (int i = 0; i < 6; i++)
1406 nodedef.tiledef[i].name = splitted[2];
1407 else if (splitted[1] == "sides")
1408 for (int i = 2; i < 6; i++)
1409 nodedef.tiledef[i].name = splitted[2];
1411 errorstream << override_filepath
1412 << ":" << line_c << " Could not apply texture override \""
1413 << line << "\": Unknown node side \""
1414 << splitted[1] << "\"" << std::endl;
1420 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1421 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1422 void *progress_callback_args)
1425 infostream << "CNodeDefManager::updateTextures(): Updating "
1426 "textures in node definitions" << std::endl;
1428 Client *client = (Client *)gamedef;
1429 ITextureSource *tsrc = client->tsrc();
1430 IShaderSource *shdsrc = client->getShaderSource();
1431 scene::IMeshManipulator *meshmanip =
1432 RenderingEngine::get_scene_manager()->getMeshManipulator();
1433 TextureSettings tsettings;
1434 tsettings.readSettings();
1436 u32 size = m_content_features.size();
1438 for (u32 i = 0; i < size; i++) {
1439 ContentFeatures *f = &(m_content_features[i]);
1440 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1441 progress_callback(progress_callback_args, i, size);
1446 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1448 writeU8(os, 1); // version
1450 std::ostringstream os2(std::ios::binary);
1451 for (u32 i = 0; i < m_content_features.size(); i++) {
1452 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1453 || i == CONTENT_UNKNOWN)
1455 const ContentFeatures *f = &m_content_features[i];
1459 // Wrap it in a string to allow different lengths without
1460 // strict version incompatibilities
1461 std::ostringstream wrapper_os(std::ios::binary);
1462 f->serialize(wrapper_os, protocol_version);
1463 os2<<serializeString(wrapper_os.str());
1465 // must not overflow
1466 u16 next = count + 1;
1467 FATAL_ERROR_IF(next < count, "Overflow");
1470 writeU16(os, count);
1471 os << serializeLongString(os2.str());
1475 void CNodeDefManager::deSerialize(std::istream &is)
1478 int version = readU8(is);
1480 throw SerializationError("unsupported NodeDefinitionManager version");
1481 u16 count = readU16(is);
1482 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1484 for (u16 n = 0; n < count; n++) {
1485 u16 i = readU16(is2);
1487 // Read it from the string wrapper
1488 std::string wrapper = deSerializeString(is2);
1489 std::istringstream wrapper_is(wrapper, std::ios::binary);
1490 f.deSerialize(wrapper_is);
1492 // Check error conditions
1493 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1494 warningstream << "NodeDefManager::deSerialize(): "
1495 "not changing builtin node " << i << std::endl;
1499 warningstream << "NodeDefManager::deSerialize(): "
1500 "received empty name" << std::endl;
1506 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1507 warningstream << "NodeDefManager::deSerialize(): "
1508 "already defined with different ID: " << f.name << std::endl;
1512 // All is ok, add node definition with the requested ID
1513 if (i >= m_content_features.size())
1514 m_content_features.resize((u32)(i) + 1);
1515 m_content_features[i] = f;
1516 addNameIdMapping(i, f.name);
1517 verbosestream << "deserialized " << f.name << std::endl;
1519 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1520 fixSelectionBoxIntUnion();
1525 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1527 m_name_id_mapping.set(i, name);
1528 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1532 IWritableNodeDefManager *createNodeDefManager()
1534 return new CNodeDefManager();
1538 //// Serialization of old ContentFeatures formats
1539 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1541 u8 compatible_param_type_2 = param_type_2;
1542 if ((protocol_version < 28)
1543 && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1544 compatible_param_type_2 = CPT2_NONE;
1545 else if (protocol_version < 30) {
1546 if (compatible_param_type_2 == CPT2_COLOR)
1547 compatible_param_type_2 = CPT2_NONE;
1548 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1549 compatible_param_type_2 = CPT2_FACEDIR;
1550 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1551 compatible_param_type_2 = CPT2_WALLMOUNTED;
1554 float compatible_visual_scale = visual_scale;
1555 if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1556 compatible_visual_scale = sqrt(visual_scale);
1558 TileDef compatible_tiles[6];
1559 for (u8 i = 0; i < 6; i++) {
1560 compatible_tiles[i] = tiledef[i];
1561 if (tiledef_overlay[i].name != "") {
1562 std::stringstream s;
1563 s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
1565 compatible_tiles[i].name = s.str();
1570 if (protocol_version < 31) {
1571 writeU8(os, protocol_version < 27 ? 7 : 8);
1573 os << serializeString(name);
1574 writeU16(os, groups.size());
1575 for (ItemGroupList::const_iterator i = groups.begin();
1576 i != groups.end(); ++i) {
1577 os << serializeString(i->first);
1578 writeS16(os, i->second);
1580 writeU8(os, drawtype);
1581 writeF1000(os, compatible_visual_scale);
1583 for (u32 i = 0; i < 6; i++)
1584 compatible_tiles[i].serialize(os, protocol_version);
1585 writeU8(os, CF_SPECIAL_COUNT);
1586 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1587 tiledef_special[i].serialize(os, protocol_version);
1589 writeU8(os, post_effect_color.getAlpha());
1590 writeU8(os, post_effect_color.getRed());
1591 writeU8(os, post_effect_color.getGreen());
1592 writeU8(os, post_effect_color.getBlue());
1593 writeU8(os, param_type);
1594 writeU8(os, compatible_param_type_2);
1595 writeU8(os, is_ground_content);
1596 writeU8(os, light_propagates);
1597 writeU8(os, sunlight_propagates);
1598 writeU8(os, walkable);
1599 writeU8(os, pointable);
1600 writeU8(os, diggable);
1601 writeU8(os, climbable);
1602 writeU8(os, buildable_to);
1603 os << serializeString(""); // legacy: used to be metadata_name
1604 writeU8(os, liquid_type);
1605 os << serializeString(liquid_alternative_flowing);
1606 os << serializeString(liquid_alternative_source);
1607 writeU8(os, liquid_viscosity);
1608 writeU8(os, liquid_renewable);
1609 writeU8(os, light_source);
1610 writeU32(os, damage_per_second);
1611 node_box.serialize(os, protocol_version);
1612 selection_box.serialize(os, protocol_version);
1613 writeU8(os, legacy_facedir_simple);
1614 writeU8(os, legacy_wallmounted);
1615 serializeSimpleSoundSpec(sound_footstep, os, 10);
1616 serializeSimpleSoundSpec(sound_dig, os, 10);
1617 serializeSimpleSoundSpec(sound_dug, os, 10);
1618 writeU8(os, rightclickable);
1619 writeU8(os, drowning);
1620 writeU8(os, leveled);
1621 writeU8(os, liquid_range);
1622 writeU8(os, waving);
1623 os << serializeString(mesh);
1624 collision_box.serialize(os, protocol_version);
1625 writeU8(os, floodable);
1626 writeU16(os, connects_to_ids.size());
1627 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1628 i != connects_to_ids.end(); ++i)
1630 writeU8(os, connect_sides);
1632 throw SerializationError("ContentFeatures::serialize(): "
1633 "Unsupported version requested");
1637 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1639 if (version == 5) // In PROTOCOL_VERSION 13
1641 name = deSerializeString(is);
1643 u32 groups_size = readU16(is);
1644 for(u32 i=0; i<groups_size; i++){
1645 std::string name = deSerializeString(is);
1646 int value = readS16(is);
1647 groups[name] = value;
1649 drawtype = (enum NodeDrawType)readU8(is);
1651 visual_scale = readF1000(is);
1652 if (readU8(is) != 6)
1653 throw SerializationError("unsupported tile count");
1654 for (u32 i = 0; i < 6; i++)
1655 tiledef[i].deSerialize(is, version, drawtype);
1656 if (readU8(is) != CF_SPECIAL_COUNT)
1657 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1658 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1659 tiledef_special[i].deSerialize(is, version, drawtype);
1661 post_effect_color.setAlpha(readU8(is));
1662 post_effect_color.setRed(readU8(is));
1663 post_effect_color.setGreen(readU8(is));
1664 post_effect_color.setBlue(readU8(is));
1665 param_type = (enum ContentParamType)readU8(is);
1666 param_type_2 = (enum ContentParamType2)readU8(is);
1667 is_ground_content = readU8(is);
1668 light_propagates = readU8(is);
1669 sunlight_propagates = readU8(is);
1670 walkable = readU8(is);
1671 pointable = readU8(is);
1672 diggable = readU8(is);
1673 climbable = readU8(is);
1674 buildable_to = readU8(is);
1675 deSerializeString(is); // legacy: used to be metadata_name
1676 liquid_type = (enum LiquidType)readU8(is);
1677 liquid_alternative_flowing = deSerializeString(is);
1678 liquid_alternative_source = deSerializeString(is);
1679 liquid_viscosity = readU8(is);
1680 light_source = readU8(is);
1681 light_source = MYMIN(light_source, LIGHT_MAX);
1682 damage_per_second = readU32(is);
1683 node_box.deSerialize(is);
1684 selection_box.deSerialize(is);
1685 legacy_facedir_simple = readU8(is);
1686 legacy_wallmounted = readU8(is);
1687 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1688 deSerializeSimpleSoundSpec(sound_dig, is, version);
1689 deSerializeSimpleSoundSpec(sound_dug, is, version);
1690 } else if (version == 6) {
1691 name = deSerializeString(is);
1693 u32 groups_size = readU16(is);
1694 for (u32 i = 0; i < groups_size; i++) {
1695 std::string name = deSerializeString(is);
1696 int value = readS16(is);
1697 groups[name] = value;
1699 drawtype = (enum NodeDrawType)readU8(is);
1700 visual_scale = readF1000(is);
1701 if (readU8(is) != 6)
1702 throw SerializationError("unsupported tile count");
1703 for (u32 i = 0; i < 6; i++)
1704 tiledef[i].deSerialize(is, version, drawtype);
1705 // CF_SPECIAL_COUNT in version 6 = 2
1706 if (readU8(is) != 2)
1707 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1708 for (u32 i = 0; i < 2; i++)
1709 tiledef_special[i].deSerialize(is, version, drawtype);
1711 post_effect_color.setAlpha(readU8(is));
1712 post_effect_color.setRed(readU8(is));
1713 post_effect_color.setGreen(readU8(is));
1714 post_effect_color.setBlue(readU8(is));
1715 param_type = (enum ContentParamType)readU8(is);
1716 param_type_2 = (enum ContentParamType2)readU8(is);
1717 is_ground_content = readU8(is);
1718 light_propagates = readU8(is);
1719 sunlight_propagates = readU8(is);
1720 walkable = readU8(is);
1721 pointable = readU8(is);
1722 diggable = readU8(is);
1723 climbable = readU8(is);
1724 buildable_to = readU8(is);
1725 deSerializeString(is); // legacy: used to be metadata_name
1726 liquid_type = (enum LiquidType)readU8(is);
1727 liquid_alternative_flowing = deSerializeString(is);
1728 liquid_alternative_source = deSerializeString(is);
1729 liquid_viscosity = readU8(is);
1730 liquid_renewable = readU8(is);
1731 light_source = readU8(is);
1732 damage_per_second = readU32(is);
1733 node_box.deSerialize(is);
1734 selection_box.deSerialize(is);
1735 legacy_facedir_simple = readU8(is);
1736 legacy_wallmounted = readU8(is);
1737 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1738 deSerializeSimpleSoundSpec(sound_dig, is, version);
1739 deSerializeSimpleSoundSpec(sound_dug, is, version);
1740 rightclickable = readU8(is);
1741 drowning = readU8(is);
1742 leveled = readU8(is);
1743 liquid_range = readU8(is);
1744 } else if (version == 7 || version == 8){
1745 name = deSerializeString(is);
1747 u32 groups_size = readU16(is);
1748 for (u32 i = 0; i < groups_size; i++) {
1749 std::string name = deSerializeString(is);
1750 int value = readS16(is);
1751 groups[name] = value;
1753 drawtype = (enum NodeDrawType) readU8(is);
1755 visual_scale = readF1000(is);
1756 if (readU8(is) != 6)
1757 throw SerializationError("unsupported tile count");
1758 for (u32 i = 0; i < 6; i++)
1759 tiledef[i].deSerialize(is, version, drawtype);
1760 if (readU8(is) != CF_SPECIAL_COUNT)
1761 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1762 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1763 tiledef_special[i].deSerialize(is, version, drawtype);
1765 post_effect_color.setAlpha(readU8(is));
1766 post_effect_color.setRed(readU8(is));
1767 post_effect_color.setGreen(readU8(is));
1768 post_effect_color.setBlue(readU8(is));
1769 param_type = (enum ContentParamType) readU8(is);
1770 param_type_2 = (enum ContentParamType2) readU8(is);
1771 is_ground_content = readU8(is);
1772 light_propagates = readU8(is);
1773 sunlight_propagates = readU8(is);
1774 walkable = readU8(is);
1775 pointable = readU8(is);
1776 diggable = readU8(is);
1777 climbable = readU8(is);
1778 buildable_to = readU8(is);
1779 deSerializeString(is); // legacy: used to be metadata_name
1780 liquid_type = (enum LiquidType) readU8(is);
1781 liquid_alternative_flowing = deSerializeString(is);
1782 liquid_alternative_source = deSerializeString(is);
1783 liquid_viscosity = readU8(is);
1784 liquid_renewable = readU8(is);
1785 light_source = readU8(is);
1786 light_source = MYMIN(light_source, LIGHT_MAX);
1787 damage_per_second = readU32(is);
1788 node_box.deSerialize(is);
1789 selection_box.deSerialize(is);
1790 legacy_facedir_simple = readU8(is);
1791 legacy_wallmounted = readU8(is);
1792 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1793 deSerializeSimpleSoundSpec(sound_dig, is, version);
1794 deSerializeSimpleSoundSpec(sound_dug, is, version);
1795 rightclickable = readU8(is);
1796 drowning = readU8(is);
1797 leveled = readU8(is);
1798 liquid_range = readU8(is);
1799 waving = readU8(is);
1801 mesh = deSerializeString(is);
1802 collision_box.deSerialize(is);
1803 floodable = readU8(is);
1804 u16 connects_to_size = readU16(is);
1805 connects_to_ids.clear();
1806 for (u16 i = 0; i < connects_to_size; i++)
1807 connects_to_ids.insert(readU16(is));
1808 connect_sides = readU8(is);
1809 } catch (SerializationError &e) {};
1811 throw SerializationError("unsupported ContentFeatures version");
1815 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1817 m_node_registration_complete = completed;
1821 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1824 if (m_node_registration_complete)
1825 nr->nodeResolveInternal();
1827 m_pending_resolve_callbacks.push_back(nr);
1831 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1833 size_t len = m_pending_resolve_callbacks.size();
1834 for (size_t i = 0; i != len; i++) {
1835 if (nr != m_pending_resolve_callbacks[i])
1839 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1840 m_pending_resolve_callbacks.resize(len);
1848 void CNodeDefManager::runNodeResolveCallbacks()
1850 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1851 NodeResolver *nr = m_pending_resolve_callbacks[i];
1852 nr->nodeResolveInternal();
1855 m_pending_resolve_callbacks.clear();
1859 void CNodeDefManager::resetNodeResolveState()
1861 m_node_registration_complete = false;
1862 m_pending_resolve_callbacks.clear();
1865 void CNodeDefManager::mapNodeboxConnections()
1867 for (u32 i = 0; i < m_content_features.size(); i++) {
1868 ContentFeatures *f = &m_content_features[i];
1869 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1871 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1872 it != f->connects_to.end(); ++it) {
1873 getIds(*it, f->connects_to_ids);
1878 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1880 const ContentFeatures &f1 = get(from);
1882 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1885 // lookup target in connected set
1886 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1889 const ContentFeatures &f2 = get(to);
1891 if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1892 // ignores actually looking if back connection exists
1893 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1895 // does to node declare usable faces?
1896 if (f2.connect_sides > 0) {
1897 if ((f2.param_type_2 == CPT2_FACEDIR ||
1898 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1899 && (connect_face >= 4)) {
1900 static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1901 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1903 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1906 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1909 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1910 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1912 return (f2.connect_sides
1913 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1915 return (f2.connect_sides & connect_face);
1917 // the target is just a regular node, so connect no matter back connection
1925 NodeResolver::NodeResolver()
1927 m_nodenames.reserve(16);
1928 m_nnlistsizes.reserve(4);
1932 NodeResolver::~NodeResolver()
1934 if (!m_resolve_done && m_ndef)
1935 m_ndef->cancelNodeResolveCallback(this);
1939 void NodeResolver::nodeResolveInternal()
1941 m_nodenames_idx = 0;
1942 m_nnlistsizes_idx = 0;
1945 m_resolve_done = true;
1947 m_nodenames.clear();
1948 m_nnlistsizes.clear();
1952 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1953 const std::string &node_alt, content_t c_fallback)
1955 if (m_nodenames_idx == m_nodenames.size()) {
1956 *result_out = c_fallback;
1957 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1962 std::string name = m_nodenames[m_nodenames_idx++];
1964 bool success = m_ndef->getId(name, c);
1965 if (!success && node_alt != "") {
1967 success = m_ndef->getId(name, c);
1971 errorstream << "NodeResolver: failed to resolve node name '" << name
1972 << "'." << std::endl;
1981 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1982 bool all_required, content_t c_fallback)
1984 bool success = true;
1986 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1987 errorstream << "NodeResolver: no more node lists" << std::endl;
1991 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1994 if (m_nodenames_idx == m_nodenames.size()) {
1995 errorstream << "NodeResolver: no more nodes in list" << std::endl;
2000 std::string &name = m_nodenames[m_nodenames_idx++];
2002 if (name.substr(0,6) != "group:") {
2003 if (m_ndef->getId(name, c)) {
2004 result_out->push_back(c);
2005 } else if (all_required) {
2006 errorstream << "NodeResolver: failed to resolve node name '"
2007 << name << "'." << std::endl;
2008 result_out->push_back(c_fallback);
2012 std::set<content_t> cids;
2013 std::set<content_t>::iterator it;
2014 m_ndef->getIds(name, cids);
2015 for (it = cids.begin(); it != cids.end(); ++it)
2016 result_out->push_back(*it);