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.
24 #include "client/tile.h"
27 #include <IMeshManipulator.h>
31 #include "nameidmapping.h"
32 #include "util/numeric.h"
33 #include "util/serialize.h"
34 #include "exceptions.h"
38 #include <fstream> // Used in applyTextureOverrides()
46 type = NODEBOX_REGULAR;
49 // default is sign/ladder-like
50 wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
51 wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
52 wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
53 // no default for other parts
55 connect_bottom.clear();
56 connect_front.clear();
59 connect_right.clear();
62 void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
66 if (protocol_version >= 27)
74 writeU8(os, NODEBOX_FIXED);
78 writeU16(os, fixed.size());
79 for (std::vector<aabb3f>::const_iterator
81 i != fixed.end(); ++i)
83 writeV3F1000(os, i->MinEdge);
84 writeV3F1000(os, i->MaxEdge);
87 case NODEBOX_WALLMOUNTED:
90 writeV3F1000(os, wall_top.MinEdge);
91 writeV3F1000(os, wall_top.MaxEdge);
92 writeV3F1000(os, wall_bottom.MinEdge);
93 writeV3F1000(os, wall_bottom.MaxEdge);
94 writeV3F1000(os, wall_side.MinEdge);
95 writeV3F1000(os, wall_side.MaxEdge);
97 case NODEBOX_CONNECTED:
99 // send old clients nodes that can't be walked through
101 writeU8(os, NODEBOX_FIXED);
104 writeV3F1000(os, v3f(-BS/2, -BS/2, -BS/2));
105 writeV3F1000(os, v3f(BS/2, BS/2, BS/2));
109 #define WRITEBOX(box) do { \
110 writeU16(os, (box).size()); \
111 for (std::vector<aabb3f>::const_iterator \
113 i != (box).end(); ++i) { \
114 writeV3F1000(os, i->MinEdge); \
115 writeV3F1000(os, i->MaxEdge); \
119 WRITEBOX(connect_top);
120 WRITEBOX(connect_bottom);
121 WRITEBOX(connect_front);
122 WRITEBOX(connect_left);
123 WRITEBOX(connect_back);
124 WRITEBOX(connect_right);
133 void NodeBox::deSerialize(std::istream &is)
135 int version = readU8(is);
136 if (version < 1 || version > 3)
137 throw SerializationError("unsupported NodeBox version");
141 type = (enum NodeBoxType)readU8(is);
143 if(type == NODEBOX_FIXED || type == NODEBOX_LEVELED)
145 u16 fixed_count = readU16(is);
149 box.MinEdge = readV3F1000(is);
150 box.MaxEdge = readV3F1000(is);
151 fixed.push_back(box);
154 else if(type == NODEBOX_WALLMOUNTED)
156 wall_top.MinEdge = readV3F1000(is);
157 wall_top.MaxEdge = readV3F1000(is);
158 wall_bottom.MinEdge = readV3F1000(is);
159 wall_bottom.MaxEdge = readV3F1000(is);
160 wall_side.MinEdge = readV3F1000(is);
161 wall_side.MaxEdge = readV3F1000(is);
163 else if (type == NODEBOX_CONNECTED)
165 #define READBOXES(box) do { \
166 count = readU16(is); \
167 (box).reserve(count); \
169 v3f min = readV3F1000(is); \
170 v3f max = readV3F1000(is); \
171 (box).push_back(aabb3f(min, max)); }; } while (0)
176 READBOXES(connect_top);
177 READBOXES(connect_bottom);
178 READBOXES(connect_front);
179 READBOXES(connect_left);
180 READBOXES(connect_back);
181 READBOXES(connect_right);
189 void TileDef::serialize(std::ostream &os, u16 protocol_version) const
191 if (protocol_version >= 30)
193 else if (protocol_version >= 29)
195 else if (protocol_version >= 26)
200 os << serializeString(name);
201 animation.serialize(os, protocol_version);
202 writeU8(os, backface_culling);
203 if (protocol_version >= 26) {
204 writeU8(os, tileable_horizontal);
205 writeU8(os, tileable_vertical);
207 if (protocol_version >= 30) {
208 writeU8(os, has_color);
210 writeU8(os, color.getRed());
211 writeU8(os, color.getGreen());
212 writeU8(os, color.getBlue());
217 void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
219 int version = readU8(is);
220 name = deSerializeString(is);
221 animation.deSerialize(is, version >= 3 ? 29 : 26);
223 backface_culling = readU8(is);
225 tileable_horizontal = readU8(is);
226 tileable_vertical = readU8(is);
229 has_color = readU8(is);
231 color.setRed(readU8(is));
232 color.setGreen(readU8(is));
233 color.setBlue(readU8(is));
237 if ((contenfeatures_version < 8) &&
238 ((drawtype == NDT_MESH) ||
239 (drawtype == NDT_FIRELIKE) ||
240 (drawtype == NDT_LIQUID) ||
241 (drawtype == NDT_PLANTLIKE)))
242 backface_culling = false;
247 SimpleSoundSpec serialization
250 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
251 std::ostream &os, u8 version)
253 os<<serializeString(ss.name);
254 writeF1000(os, ss.gain);
257 writeF1000(os, ss.pitch);
259 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is, u8 version)
261 ss.name = deSerializeString(is);
262 ss.gain = readF1000(is);
265 ss.pitch = readF1000(is);
268 void TextureSettings::readSettings()
270 connected_glass = g_settings->getBool("connected_glass");
271 opaque_water = g_settings->getBool("opaque_water");
272 bool enable_shaders = g_settings->getBool("enable_shaders");
273 bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
274 bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
275 bool smooth_lighting = g_settings->getBool("smooth_lighting");
276 enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
277 enable_minimap = g_settings->getBool("enable_minimap");
278 std::string leaves_style_str = g_settings->get("leaves_style");
280 // Mesh cache is not supported in combination with smooth lighting
282 enable_mesh_cache = false;
284 use_normal_texture = enable_shaders &&
285 (enable_bumpmapping || enable_parallax_occlusion);
286 if (leaves_style_str == "fancy") {
287 leaves_style = LEAVES_FANCY;
288 } else if (leaves_style_str == "simple") {
289 leaves_style = LEAVES_SIMPLE;
291 leaves_style = LEAVES_OPAQUE;
299 ContentFeatures::ContentFeatures()
304 ContentFeatures::~ContentFeatures()
308 void ContentFeatures::reset()
315 visual_solidness = 0;
316 backface_culling = true;
319 has_on_construct = false;
320 has_on_destruct = false;
321 has_after_destruct = false;
325 NOTE: Most of this is always overridden by the default values given
330 // Unknown nodes can be dug
331 groups["dig_immediate"] = 2;
332 drawtype = NDT_NORMAL;
335 for(u32 i = 0; i < 24; i++)
337 minimap_color = video::SColor(0, 0, 0, 0);
340 for(u32 i = 0; i < 6; i++)
341 tiledef[i] = TileDef();
342 for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
343 tiledef_special[j] = TileDef();
345 post_effect_color = video::SColor(0, 0, 0, 0);
346 param_type = CPT_NONE;
347 param_type_2 = CPT2_NONE;
348 is_ground_content = false;
349 light_propagates = false;
350 sunlight_propagates = false;
355 buildable_to = false;
357 rightclickable = true;
359 liquid_type = LIQUID_NONE;
360 liquid_alternative_flowing = "";
361 liquid_alternative_source = "";
362 liquid_viscosity = 0;
363 liquid_renewable = true;
364 liquid_range = LIQUID_LEVEL_MAX+1;
367 damage_per_second = 0;
368 node_box = NodeBox();
369 selection_box = NodeBox();
370 collision_box = NodeBox();
372 legacy_facedir_simple = false;
373 legacy_wallmounted = false;
374 sound_footstep = SimpleSoundSpec();
375 sound_dig = SimpleSoundSpec("__group");
376 sound_dug = SimpleSoundSpec();
378 connects_to_ids.clear();
380 color = video::SColor(0xFFFFFFFF);
385 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
387 if (protocol_version < 31) {
388 serializeOld(os, protocol_version);
393 u8 version = (protocol_version >= 34) ? 11 : 10;
394 writeU8(os, version);
397 os << serializeString(name);
398 writeU16(os, groups.size());
399 for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
401 os << serializeString(i->first);
402 writeS16(os, i->second);
404 writeU8(os, param_type);
405 writeU8(os, param_type_2);
408 writeU8(os, drawtype);
409 os << serializeString(mesh);
410 writeF1000(os, visual_scale);
412 for (u32 i = 0; i < 6; i++)
413 tiledef[i].serialize(os, protocol_version);
414 for (u32 i = 0; i < 6; i++)
415 tiledef_overlay[i].serialize(os, protocol_version);
416 writeU8(os, CF_SPECIAL_COUNT);
417 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
418 tiledef_special[i].serialize(os, protocol_version);
421 writeU8(os, color.getRed());
422 writeU8(os, color.getGreen());
423 writeU8(os, color.getBlue());
424 os << serializeString(palette_name);
426 writeU8(os, connect_sides);
427 writeU16(os, connects_to_ids.size());
428 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
429 i != connects_to_ids.end(); ++i)
431 writeU8(os, post_effect_color.getAlpha());
432 writeU8(os, post_effect_color.getRed());
433 writeU8(os, post_effect_color.getGreen());
434 writeU8(os, post_effect_color.getBlue());
435 writeU8(os, leveled);
438 writeU8(os, light_propagates);
439 writeU8(os, sunlight_propagates);
440 writeU8(os, light_source);
443 writeU8(os, is_ground_content);
446 writeU8(os, walkable);
447 writeU8(os, pointable);
448 writeU8(os, diggable);
449 writeU8(os, climbable);
450 writeU8(os, buildable_to);
451 writeU8(os, rightclickable);
452 writeU32(os, damage_per_second);
455 writeU8(os, liquid_type);
456 os << serializeString(liquid_alternative_flowing);
457 os << serializeString(liquid_alternative_source);
458 writeU8(os, liquid_viscosity);
459 writeU8(os, liquid_renewable);
460 writeU8(os, liquid_range);
461 writeU8(os, drowning);
462 writeU8(os, floodable);
465 node_box.serialize(os, protocol_version);
466 selection_box.serialize(os, protocol_version);
467 collision_box.serialize(os, protocol_version);
470 serializeSimpleSoundSpec(sound_footstep, os, version);
471 serializeSimpleSoundSpec(sound_dig, os, version);
472 serializeSimpleSoundSpec(sound_dug, os, version);
475 writeU8(os, legacy_facedir_simple);
476 writeU8(os, legacy_wallmounted);
479 void ContentFeatures::correctAlpha(TileDef *tiles, int length)
481 // alpha == 0 means that the node is using texture alpha
482 if (alpha == 0 || alpha == 255)
485 for (int i = 0; i < length; i++) {
486 if (tiles[i].name == "")
489 s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha);
490 tiles[i].name = s.str();
494 void ContentFeatures::deSerialize(std::istream &is)
497 int version = readU8(is);
499 deSerializeOld(is, version);
501 } else if (version > 11) {
502 throw SerializationError("unsupported ContentFeatures version");
506 name = deSerializeString(is);
508 u32 groups_size = readU16(is);
509 for (u32 i = 0; i < groups_size; i++) {
510 std::string name = deSerializeString(is);
511 int value = readS16(is);
512 groups[name] = value;
514 param_type = (enum ContentParamType) readU8(is);
515 param_type_2 = (enum ContentParamType2) readU8(is);
518 drawtype = (enum NodeDrawType) readU8(is);
519 mesh = deSerializeString(is);
520 visual_scale = readF1000(is);
522 throw SerializationError("unsupported tile count");
523 for (u32 i = 0; i < 6; i++)
524 tiledef[i].deSerialize(is, version, drawtype);
526 for (u32 i = 0; i < 6; i++)
527 tiledef_overlay[i].deSerialize(is, version, drawtype);
528 if (readU8(is) != CF_SPECIAL_COUNT)
529 throw SerializationError("unsupported CF_SPECIAL_COUNT");
530 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
531 tiledef_special[i].deSerialize(is, version, drawtype);
533 color.setRed(readU8(is));
534 color.setGreen(readU8(is));
535 color.setBlue(readU8(is));
536 palette_name = deSerializeString(is);
538 connect_sides = readU8(is);
539 u16 connects_to_size = readU16(is);
540 connects_to_ids.clear();
541 for (u16 i = 0; i < connects_to_size; i++)
542 connects_to_ids.insert(readU16(is));
543 post_effect_color.setAlpha(readU8(is));
544 post_effect_color.setRed(readU8(is));
545 post_effect_color.setGreen(readU8(is));
546 post_effect_color.setBlue(readU8(is));
547 leveled = readU8(is);
550 light_propagates = readU8(is);
551 sunlight_propagates = readU8(is);
552 light_source = readU8(is);
553 light_source = MYMIN(light_source, LIGHT_MAX);
556 is_ground_content = readU8(is);
559 walkable = readU8(is);
560 pointable = readU8(is);
561 diggable = readU8(is);
562 climbable = readU8(is);
563 buildable_to = readU8(is);
564 rightclickable = readU8(is);
565 damage_per_second = readU32(is);
568 liquid_type = (enum LiquidType) readU8(is);
569 liquid_alternative_flowing = deSerializeString(is);
570 liquid_alternative_source = deSerializeString(is);
571 liquid_viscosity = readU8(is);
572 liquid_renewable = readU8(is);
573 liquid_range = readU8(is);
574 drowning = readU8(is);
575 floodable = readU8(is);
578 node_box.deSerialize(is);
579 selection_box.deSerialize(is);
580 collision_box.deSerialize(is);
583 deSerializeSimpleSoundSpec(sound_footstep, is, version);
584 deSerializeSimpleSoundSpec(sound_dig, is, version);
585 deSerializeSimpleSoundSpec(sound_dug, is, version);
587 // read legacy properties
588 legacy_facedir_simple = readU8(is);
589 legacy_wallmounted = readU8(is);
593 void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *tile,
594 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
595 bool backface_culling, u8 material_type)
597 tile->shader_id = shader_id;
598 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
599 tile->material_type = material_type;
601 // Normal texture and shader flags texture
602 if (use_normal_texture) {
603 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
605 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
608 tile->material_flags = 0;
609 if (backface_culling)
610 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
611 if (tiledef->animation.type != TAT_NONE)
612 tile->material_flags |= MATERIAL_FLAG_ANIMATION;
613 if (tiledef->tileable_horizontal)
614 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
615 if (tiledef->tileable_vertical)
616 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
619 tile->has_color = tiledef->has_color;
620 if (tiledef->has_color)
621 tile->color = tiledef->color;
625 // Animation parameters
627 if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
629 tiledef->animation.determineParams(tile->texture->getOriginalSize(),
630 &frame_count, &frame_length_ms, NULL);
631 tile->animation_frame_count = frame_count;
632 tile->animation_frame_length_ms = frame_length_ms;
635 if (frame_count == 1) {
636 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
638 std::ostringstream os(std::ios::binary);
639 tile->frames.resize(frame_count);
641 for (int i = 0; i < frame_count; i++) {
647 tiledef->animation.getTextureModifer(os,
648 tile->texture->getOriginalSize(), i);
650 frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
651 if (tile->normal_texture)
652 frame.normal_texture = tsrc->getNormalTexture(os.str());
653 frame.flags_texture = tile->flags_texture;
654 tile->frames[i] = frame;
661 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
662 scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
664 // minimap pixel color - the average color of a texture
665 if (tsettings.enable_minimap && tiledef[0].name != "")
666 minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
668 // Figure out the actual tiles to use
670 for (u32 j = 0; j < 6; j++) {
671 tdef[j] = tiledef[j];
672 if (tdef[j].name == "")
673 tdef[j].name = "unknown_node.png";
675 // also the overlay tiles
676 TileDef tdef_overlay[6];
677 for (u32 j = 0; j < 6; j++)
678 tdef_overlay[j] = tiledef_overlay[j];
679 // also the special tiles
680 TileDef tdef_spec[6];
681 for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
682 tdef_spec[j] = tiledef_special[j];
684 bool is_liquid = false;
686 u8 material_type = (alpha == 255) ?
687 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
698 assert(liquid_type == LIQUID_SOURCE);
699 if (tsettings.opaque_water)
704 case NDT_FLOWINGLIQUID:
705 assert(liquid_type == LIQUID_FLOWING);
707 if (tsettings.opaque_water)
713 visual_solidness = 1;
715 case NDT_GLASSLIKE_FRAMED:
717 visual_solidness = 1;
719 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
721 visual_solidness = 1;
722 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
726 visual_solidness = 1;
728 case NDT_ALLFACES_OPTIONAL:
729 if (tsettings.leaves_style == LEAVES_FANCY) {
730 drawtype = NDT_ALLFACES;
732 visual_solidness = 1;
733 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
734 for (u32 j = 0; j < 6; j++) {
735 if (tdef_spec[j].name != "")
736 tdef[j].name = tdef_spec[j].name;
738 drawtype = NDT_GLASSLIKE;
740 visual_solidness = 1;
742 drawtype = NDT_NORMAL;
744 for (u32 i = 0; i < 6; i++)
745 tdef[i].name += std::string("^[noalpha");
748 material_type = TILE_MATERIAL_WAVING_LEAVES;
753 material_type = TILE_MATERIAL_WAVING_PLANTS;
762 material_type = TILE_MATERIAL_WAVING_PLANTS;
763 else if (waving == 2)
764 material_type = TILE_MATERIAL_WAVING_LEAVES;
775 // Vertex alpha is no longer supported, correct if necessary.
776 correctAlpha(tdef, 6);
777 correctAlpha(tdef_overlay, 6);
778 correctAlpha(tdef_spec, CF_SPECIAL_COUNT);
779 material_type = (alpha == 255) ?
780 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
784 for (u16 j = 0; j < 6; j++) {
785 tile_shader[j] = shdsrc->getShader("nodes_shader",
786 material_type, drawtype);
789 // Tiles (fill in f->tiles[])
790 for (u16 j = 0; j < 6; j++) {
791 fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
792 tsettings.use_normal_texture,
793 tdef[j].backface_culling, material_type);
794 if (tdef_overlay[j].name != "")
795 fillTileAttribs(tsrc, &tiles[j].layers[1], &tdef_overlay[j],
796 tile_shader[j], tsettings.use_normal_texture,
797 tdef[j].backface_culling, material_type);
800 // Special tiles (fill in f->special_tiles[])
801 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
802 fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tdef_spec[j],
803 tile_shader[j], tsettings.use_normal_texture,
804 tdef_spec[j].backface_culling, material_type);
807 if (param_type_2 == CPT2_COLOR ||
808 param_type_2 == CPT2_COLORED_FACEDIR ||
809 param_type_2 == CPT2_COLORED_WALLMOUNTED)
810 palette = tsrc->getPalette(palette_name);
812 if ((drawtype == NDT_MESH) && (mesh != "")) {
814 // Read the mesh and apply scale
815 mesh_ptr[0] = client->getMesh(mesh);
817 v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
818 scaleMesh(mesh_ptr[0], scale);
819 recalculateBoundingBox(mesh_ptr[0]);
820 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
822 } else if ((drawtype == NDT_NODEBOX) &&
823 ((node_box.type == NODEBOX_REGULAR) ||
824 (node_box.type == NODEBOX_FIXED)) &&
825 (!node_box.fixed.empty())) {
826 //Convert regular nodebox nodes to meshnodes
827 //Change the drawtype and apply scale
829 mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
830 v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
831 scaleMesh(mesh_ptr[0], scale);
832 recalculateBoundingBox(mesh_ptr[0]);
833 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
836 //Cache 6dfacedir and wallmounted rotated clones of meshes
837 if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
838 (param_type_2 == CPT2_FACEDIR
839 || param_type_2 == CPT2_COLORED_FACEDIR)) {
840 for (u16 j = 1; j < 24; j++) {
841 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
842 rotateMeshBy6dFacedir(mesh_ptr[j], j);
843 recalculateBoundingBox(mesh_ptr[j]);
844 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
846 } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
847 && (param_type_2 == CPT2_WALLMOUNTED ||
848 param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
849 static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
850 for (u16 j = 1; j < 6; j++) {
851 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
852 rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
853 recalculateBoundingBox(mesh_ptr[j]);
854 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
856 rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
857 recalculateBoundingBox(mesh_ptr[0]);
858 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
867 class CNodeDefManager: public IWritableNodeDefManager {
870 virtual ~CNodeDefManager();
872 virtual IWritableNodeDefManager *clone();
873 inline virtual const ContentFeatures& get(content_t c) const;
874 inline virtual const ContentFeatures& get(const MapNode &n) const;
875 virtual bool getId(const std::string &name, content_t &result) const;
876 virtual content_t getId(const std::string &name) const;
877 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
878 virtual const ContentFeatures& get(const std::string &name) const;
879 content_t allocateId();
880 virtual content_t set(const std::string &name, const ContentFeatures &def);
881 virtual content_t allocateDummy(const std::string &name);
882 virtual void removeNode(const std::string &name);
883 virtual void updateAliases(IItemDefManager *idef);
884 virtual void applyTextureOverrides(const std::string &override_filepath);
885 virtual void updateTextures(IGameDef *gamedef,
886 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
887 void *progress_cbk_args);
888 void serialize(std::ostream &os, u16 protocol_version) const;
889 void deSerialize(std::istream &is);
891 inline virtual void setNodeRegistrationStatus(bool completed);
893 virtual void pendNodeResolve(NodeResolver *nr);
894 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
895 virtual void runNodeResolveCallbacks();
896 virtual void resetNodeResolveState();
897 virtual void mapNodeboxConnections();
898 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
899 virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
901 return m_selection_box_int_union;
905 void addNameIdMapping(content_t i, std::string name);
907 * Recalculates m_selection_box_int_union based on
908 * m_selection_box_union.
910 void fixSelectionBoxIntUnion();
912 // Features indexed by id
913 std::vector<ContentFeatures> m_content_features;
915 // A mapping for fast converting back and forth between names and ids
916 NameIdMapping m_name_id_mapping;
918 // Like m_name_id_mapping, but only from names to ids, and includes
919 // item aliases too. Updated by updateAliases()
920 // Note: Not serialized.
922 std::unordered_map<std::string, content_t> m_name_id_mapping_with_aliases;
924 // A mapping from groups to a list of content_ts (and their levels)
925 // that belong to it. Necessary for a direct lookup in getIds().
926 // Note: Not serialized.
927 std::unordered_map<std::string, GroupItems> m_group_to_items;
929 // Next possibly free id
932 // NodeResolvers to callback once node registration has ended
933 std::vector<NodeResolver *> m_pending_resolve_callbacks;
935 // True when all nodes have been registered
936 bool m_node_registration_complete;
938 //! The union of all nodes' selection boxes.
939 aabb3f m_selection_box_union;
941 * The smallest box in node coordinates that
942 * contains all nodes' selection boxes.
944 core::aabbox3d<s16> m_selection_box_int_union;
948 CNodeDefManager::CNodeDefManager()
954 CNodeDefManager::~CNodeDefManager()
957 for (u32 i = 0; i < m_content_features.size(); i++) {
958 ContentFeatures *f = &m_content_features[i];
959 for (u32 j = 0; j < 24; j++) {
961 f->mesh_ptr[j]->drop();
968 void CNodeDefManager::clear()
970 m_content_features.clear();
971 m_name_id_mapping.clear();
972 m_name_id_mapping_with_aliases.clear();
973 m_group_to_items.clear();
975 m_selection_box_union.reset(0,0,0);
976 m_selection_box_int_union.reset(0,0,0);
978 resetNodeResolveState();
980 u32 initial_length = 0;
981 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
982 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
983 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
984 m_content_features.resize(initial_length);
986 // Set CONTENT_UNKNOWN
990 // Insert directly into containers
991 content_t c = CONTENT_UNKNOWN;
992 m_content_features[c] = f;
993 addNameIdMapping(c, f.name);
1000 f.drawtype = NDT_AIRLIKE;
1001 f.param_type = CPT_LIGHT;
1002 f.light_propagates = true;
1003 f.sunlight_propagates = true;
1005 f.pointable = false;
1007 f.buildable_to = true;
1009 f.is_ground_content = true;
1010 // Insert directly into containers
1011 content_t c = CONTENT_AIR;
1012 m_content_features[c] = f;
1013 addNameIdMapping(c, f.name);
1016 // Set CONTENT_IGNORE
1020 f.drawtype = NDT_AIRLIKE;
1021 f.param_type = CPT_NONE;
1022 f.light_propagates = false;
1023 f.sunlight_propagates = false;
1025 f.pointable = false;
1027 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
1028 f.is_ground_content = true;
1029 // Insert directly into containers
1030 content_t c = CONTENT_IGNORE;
1031 m_content_features[c] = f;
1032 addNameIdMapping(c, f.name);
1037 IWritableNodeDefManager *CNodeDefManager::clone()
1039 CNodeDefManager *mgr = new CNodeDefManager();
1045 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1047 return c < m_content_features.size()
1048 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1052 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1054 return get(n.getContent());
1058 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1060 std::unordered_map<std::string, content_t>::const_iterator
1061 i = m_name_id_mapping_with_aliases.find(name);
1062 if(i == m_name_id_mapping_with_aliases.end())
1069 content_t CNodeDefManager::getId(const std::string &name) const
1071 content_t id = CONTENT_IGNORE;
1077 bool CNodeDefManager::getIds(const std::string &name,
1078 std::set<content_t> &result) const
1080 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1081 if (name.substr(0,6) != "group:") {
1082 content_t id = CONTENT_IGNORE;
1083 bool exists = getId(name, id);
1088 std::string group = name.substr(6);
1090 std::unordered_map<std::string, GroupItems>::const_iterator
1091 i = m_group_to_items.find(group);
1092 if (i == m_group_to_items.end())
1095 const GroupItems &items = i->second;
1096 for (GroupItems::const_iterator j = items.begin();
1097 j != items.end(); ++j) {
1098 if ((*j).second != 0)
1099 result.insert((*j).first);
1101 //printf("getIds: %dus\n", t.stop());
1106 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1108 content_t id = CONTENT_UNKNOWN;
1114 // returns CONTENT_IGNORE if no free ID found
1115 content_t CNodeDefManager::allocateId()
1117 for (content_t id = m_next_id;
1118 id >= m_next_id; // overflow?
1120 while (id >= m_content_features.size()) {
1121 m_content_features.push_back(ContentFeatures());
1123 const ContentFeatures &f = m_content_features[id];
1129 // If we arrive here, an overflow occurred in id.
1130 // That means no ID was found
1131 return CONTENT_IGNORE;
1136 * Returns the smallest box that contains all boxes
1137 * in the vector. Box_union is expanded.
1138 * @param[in] boxes the vector containing the boxes
1139 * @param[in, out] box_union the union of the arguments
1141 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1143 for (std::vector<aabb3f>::const_iterator it = boxes.begin();
1144 it != boxes.end(); ++it) {
1145 box_union->addInternalBox(*it);
1151 * Returns a box that contains the nodebox in every case.
1152 * The argument node_union is expanded.
1153 * @param[in] nodebox the nodebox to be measured
1154 * @param[in] features used to decide whether the nodebox
1156 * @param[in, out] box_union the union of the arguments
1158 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1161 switch(nodebox.type) {
1163 case NODEBOX_LEVELED: {
1165 aabb3f half_processed(0, 0, 0, 0, 0, 0);
1166 boxVectorUnion(nodebox.fixed, &half_processed);
1167 // Set leveled boxes to maximal
1168 if (nodebox.type == NODEBOX_LEVELED) {
1169 half_processed.MaxEdge.Y = +BS / 2;
1171 if (features.param_type_2 == CPT2_FACEDIR ||
1172 features.param_type_2 == CPT2_COLORED_FACEDIR) {
1173 // Get maximal coordinate
1175 fabsf(half_processed.MinEdge.X),
1176 fabsf(half_processed.MinEdge.Y),
1177 fabsf(half_processed.MinEdge.Z),
1178 fabsf(half_processed.MaxEdge.X),
1179 fabsf(half_processed.MaxEdge.Y),
1180 fabsf(half_processed.MaxEdge.Z) };
1182 for (int i = 0; i < 6; i++) {
1183 if (max < coords[i]) {
1187 // Add the union of all possible rotated boxes
1188 box_union->addInternalPoint(-max, -max, -max);
1189 box_union->addInternalPoint(+max, +max, +max);
1191 box_union->addInternalBox(half_processed);
1195 case NODEBOX_WALLMOUNTED: {
1197 box_union->addInternalBox(nodebox.wall_top);
1198 box_union->addInternalBox(nodebox.wall_bottom);
1199 // Find maximal coordinate in the X-Z plane
1201 fabsf(nodebox.wall_side.MinEdge.X),
1202 fabsf(nodebox.wall_side.MinEdge.Z),
1203 fabsf(nodebox.wall_side.MaxEdge.X),
1204 fabsf(nodebox.wall_side.MaxEdge.Z) };
1206 for (int i = 0; i < 4; i++) {
1207 if (max < coords[i]) {
1211 // Add the union of all possible rotated boxes
1212 box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1213 box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1216 case NODEBOX_CONNECTED: {
1217 // Add all possible connected boxes
1218 boxVectorUnion(nodebox.fixed, box_union);
1219 boxVectorUnion(nodebox.connect_top, box_union);
1220 boxVectorUnion(nodebox.connect_bottom, box_union);
1221 boxVectorUnion(nodebox.connect_front, box_union);
1222 boxVectorUnion(nodebox.connect_left, box_union);
1223 boxVectorUnion(nodebox.connect_back, box_union);
1224 boxVectorUnion(nodebox.connect_right, box_union);
1229 box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1230 box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1236 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1238 m_selection_box_int_union.MinEdge.X = floorf(
1239 m_selection_box_union.MinEdge.X / BS + 0.5f);
1240 m_selection_box_int_union.MinEdge.Y = floorf(
1241 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1242 m_selection_box_int_union.MinEdge.Z = floorf(
1243 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1244 m_selection_box_int_union.MaxEdge.X = ceilf(
1245 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1246 m_selection_box_int_union.MaxEdge.Y = ceilf(
1247 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1248 m_selection_box_int_union.MaxEdge.Z = ceilf(
1249 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1253 // IWritableNodeDefManager
1254 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1258 assert(name == def.name);
1260 // Don't allow redefining ignore (but allow air and unknown)
1261 if (name == "ignore") {
1262 warningstream << "NodeDefManager: Ignoring "
1263 "CONTENT_IGNORE redefinition"<<std::endl;
1264 return CONTENT_IGNORE;
1267 content_t id = CONTENT_IGNORE;
1268 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1271 if (id == CONTENT_IGNORE) {
1272 warningstream << "NodeDefManager: Absolute "
1273 "limit reached" << std::endl;
1274 return CONTENT_IGNORE;
1276 assert(id != CONTENT_IGNORE);
1277 addNameIdMapping(id, name);
1279 m_content_features[id] = def;
1280 verbosestream << "NodeDefManager: registering content id \"" << id
1281 << "\": name=\"" << def.name << "\""<<std::endl;
1283 getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1284 fixSelectionBoxIntUnion();
1285 // Add this content to the list of all groups it belongs to
1286 // FIXME: This should remove a node from groups it no longer
1287 // belongs to when a node is re-registered
1288 for (ItemGroupList::const_iterator i = def.groups.begin();
1289 i != def.groups.end(); ++i) {
1290 std::string group_name = i->first;
1292 std::unordered_map<std::string, GroupItems>::iterator
1293 j = m_group_to_items.find(group_name);
1294 if (j == m_group_to_items.end()) {
1295 m_group_to_items[group_name].push_back(
1296 std::make_pair(id, i->second));
1298 GroupItems &items = j->second;
1299 items.push_back(std::make_pair(id, i->second));
1306 content_t CNodeDefManager::allocateDummy(const std::string &name)
1308 assert(name != ""); // Pre-condition
1311 return set(name, f);
1315 void CNodeDefManager::removeNode(const std::string &name)
1320 // Erase name from name ID mapping
1321 content_t id = CONTENT_IGNORE;
1322 if (m_name_id_mapping.getId(name, id)) {
1323 m_name_id_mapping.eraseName(name);
1324 m_name_id_mapping_with_aliases.erase(name);
1327 // Erase node content from all groups it belongs to
1328 for (std::unordered_map<std::string, GroupItems>::iterator iter_groups =
1329 m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1330 GroupItems &items = iter_groups->second;
1331 for (GroupItems::iterator iter_groupitems = items.begin();
1332 iter_groupitems != items.end();) {
1333 if (iter_groupitems->first == id)
1334 items.erase(iter_groupitems++);
1339 // Check if group is empty
1340 if (items.size() == 0)
1341 m_group_to_items.erase(iter_groups++);
1348 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1350 std::set<std::string> all;
1352 m_name_id_mapping_with_aliases.clear();
1353 for (std::set<std::string>::const_iterator
1354 i = all.begin(); i != all.end(); ++i) {
1355 const std::string &name = *i;
1356 const std::string &convert_to = idef->getAlias(name);
1358 if (m_name_id_mapping.getId(convert_to, id)) {
1359 m_name_id_mapping_with_aliases.insert(
1360 std::make_pair(name, id));
1365 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1367 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1368 "overrides to textures from " << override_filepath << std::endl;
1370 std::ifstream infile(override_filepath.c_str());
1373 while (std::getline(infile, line)) {
1375 if (trim(line) == "")
1377 std::vector<std::string> splitted = str_split(line, ' ');
1378 if (splitted.size() != 3) {
1379 errorstream << override_filepath
1380 << ":" << line_c << " Could not apply texture override \""
1381 << line << "\": Syntax error" << std::endl;
1386 if (!getId(splitted[0], id))
1387 continue; // Ignore unknown node
1389 ContentFeatures &nodedef = m_content_features[id];
1391 if (splitted[1] == "top")
1392 nodedef.tiledef[0].name = splitted[2];
1393 else if (splitted[1] == "bottom")
1394 nodedef.tiledef[1].name = splitted[2];
1395 else if (splitted[1] == "right")
1396 nodedef.tiledef[2].name = splitted[2];
1397 else if (splitted[1] == "left")
1398 nodedef.tiledef[3].name = splitted[2];
1399 else if (splitted[1] == "back")
1400 nodedef.tiledef[4].name = splitted[2];
1401 else if (splitted[1] == "front")
1402 nodedef.tiledef[5].name = splitted[2];
1403 else if (splitted[1] == "all" || splitted[1] == "*")
1404 for (int i = 0; i < 6; i++)
1405 nodedef.tiledef[i].name = splitted[2];
1406 else if (splitted[1] == "sides")
1407 for (int i = 2; i < 6; i++)
1408 nodedef.tiledef[i].name = splitted[2];
1410 errorstream << override_filepath
1411 << ":" << line_c << " Could not apply texture override \""
1412 << line << "\": Unknown node side \""
1413 << splitted[1] << "\"" << std::endl;
1419 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1420 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1421 void *progress_callback_args)
1424 infostream << "CNodeDefManager::updateTextures(): Updating "
1425 "textures in node definitions" << std::endl;
1427 Client *client = (Client *)gamedef;
1428 ITextureSource *tsrc = client->tsrc();
1429 IShaderSource *shdsrc = client->getShaderSource();
1430 scene::ISceneManager* smgr = client->getSceneManager();
1431 scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1432 TextureSettings tsettings;
1433 tsettings.readSettings();
1435 u32 size = m_content_features.size();
1437 for (u32 i = 0; i < size; i++) {
1438 ContentFeatures *f = &(m_content_features[i]);
1439 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1440 progress_callback(progress_callback_args, i, size);
1445 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1447 writeU8(os, 1); // version
1449 std::ostringstream os2(std::ios::binary);
1450 for (u32 i = 0; i < m_content_features.size(); i++) {
1451 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1452 || i == CONTENT_UNKNOWN)
1454 const ContentFeatures *f = &m_content_features[i];
1458 // Wrap it in a string to allow different lengths without
1459 // strict version incompatibilities
1460 std::ostringstream wrapper_os(std::ios::binary);
1461 f->serialize(wrapper_os, protocol_version);
1462 os2<<serializeString(wrapper_os.str());
1464 // must not overflow
1465 u16 next = count + 1;
1466 FATAL_ERROR_IF(next < count, "Overflow");
1469 writeU16(os, count);
1470 os << serializeLongString(os2.str());
1474 void CNodeDefManager::deSerialize(std::istream &is)
1477 int version = readU8(is);
1479 throw SerializationError("unsupported NodeDefinitionManager version");
1480 u16 count = readU16(is);
1481 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1483 for (u16 n = 0; n < count; n++) {
1484 u16 i = readU16(is2);
1486 // Read it from the string wrapper
1487 std::string wrapper = deSerializeString(is2);
1488 std::istringstream wrapper_is(wrapper, std::ios::binary);
1489 f.deSerialize(wrapper_is);
1491 // Check error conditions
1492 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1493 warningstream << "NodeDefManager::deSerialize(): "
1494 "not changing builtin node " << i << std::endl;
1498 warningstream << "NodeDefManager::deSerialize(): "
1499 "received empty name" << std::endl;
1505 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1506 warningstream << "NodeDefManager::deSerialize(): "
1507 "already defined with different ID: " << f.name << std::endl;
1511 // All is ok, add node definition with the requested ID
1512 if (i >= m_content_features.size())
1513 m_content_features.resize((u32)(i) + 1);
1514 m_content_features[i] = f;
1515 addNameIdMapping(i, f.name);
1516 verbosestream << "deserialized " << f.name << std::endl;
1518 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1519 fixSelectionBoxIntUnion();
1524 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1526 m_name_id_mapping.set(i, name);
1527 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1531 IWritableNodeDefManager *createNodeDefManager()
1533 return new CNodeDefManager();
1537 //// Serialization of old ContentFeatures formats
1538 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1540 u8 compatible_param_type_2 = param_type_2;
1541 if ((protocol_version < 28)
1542 && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1543 compatible_param_type_2 = CPT2_NONE;
1544 else if (protocol_version < 30) {
1545 if (compatible_param_type_2 == CPT2_COLOR)
1546 compatible_param_type_2 = CPT2_NONE;
1547 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1548 compatible_param_type_2 = CPT2_FACEDIR;
1549 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1550 compatible_param_type_2 = CPT2_WALLMOUNTED;
1553 float compatible_visual_scale = visual_scale;
1554 if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1555 compatible_visual_scale = sqrt(visual_scale);
1557 TileDef compatible_tiles[6];
1558 for (u8 i = 0; i < 6; i++) {
1559 compatible_tiles[i] = tiledef[i];
1560 if (tiledef_overlay[i].name != "") {
1561 std::stringstream s;
1562 s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
1564 compatible_tiles[i].name = s.str();
1569 if (protocol_version < 31) {
1570 writeU8(os, protocol_version < 27 ? 7 : 8);
1572 os << serializeString(name);
1573 writeU16(os, groups.size());
1574 for (ItemGroupList::const_iterator i = groups.begin();
1575 i != groups.end(); ++i) {
1576 os << serializeString(i->first);
1577 writeS16(os, i->second);
1579 writeU8(os, drawtype);
1580 writeF1000(os, compatible_visual_scale);
1582 for (u32 i = 0; i < 6; i++)
1583 compatible_tiles[i].serialize(os, protocol_version);
1584 writeU8(os, CF_SPECIAL_COUNT);
1585 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1586 tiledef_special[i].serialize(os, protocol_version);
1588 writeU8(os, post_effect_color.getAlpha());
1589 writeU8(os, post_effect_color.getRed());
1590 writeU8(os, post_effect_color.getGreen());
1591 writeU8(os, post_effect_color.getBlue());
1592 writeU8(os, param_type);
1593 writeU8(os, compatible_param_type_2);
1594 writeU8(os, is_ground_content);
1595 writeU8(os, light_propagates);
1596 writeU8(os, sunlight_propagates);
1597 writeU8(os, walkable);
1598 writeU8(os, pointable);
1599 writeU8(os, diggable);
1600 writeU8(os, climbable);
1601 writeU8(os, buildable_to);
1602 os << serializeString(""); // legacy: used to be metadata_name
1603 writeU8(os, liquid_type);
1604 os << serializeString(liquid_alternative_flowing);
1605 os << serializeString(liquid_alternative_source);
1606 writeU8(os, liquid_viscosity);
1607 writeU8(os, liquid_renewable);
1608 writeU8(os, light_source);
1609 writeU32(os, damage_per_second);
1610 node_box.serialize(os, protocol_version);
1611 selection_box.serialize(os, protocol_version);
1612 writeU8(os, legacy_facedir_simple);
1613 writeU8(os, legacy_wallmounted);
1614 serializeSimpleSoundSpec(sound_footstep, os, 10);
1615 serializeSimpleSoundSpec(sound_dig, os, 10);
1616 serializeSimpleSoundSpec(sound_dug, os, 10);
1617 writeU8(os, rightclickable);
1618 writeU8(os, drowning);
1619 writeU8(os, leveled);
1620 writeU8(os, liquid_range);
1621 writeU8(os, waving);
1622 os << serializeString(mesh);
1623 collision_box.serialize(os, protocol_version);
1624 writeU8(os, floodable);
1625 writeU16(os, connects_to_ids.size());
1626 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1627 i != connects_to_ids.end(); ++i)
1629 writeU8(os, connect_sides);
1631 throw SerializationError("ContentFeatures::serialize(): "
1632 "Unsupported version requested");
1636 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1638 if (version == 5) // In PROTOCOL_VERSION 13
1640 name = deSerializeString(is);
1642 u32 groups_size = readU16(is);
1643 for(u32 i=0; i<groups_size; i++){
1644 std::string name = deSerializeString(is);
1645 int value = readS16(is);
1646 groups[name] = value;
1648 drawtype = (enum NodeDrawType)readU8(is);
1650 visual_scale = readF1000(is);
1651 if (readU8(is) != 6)
1652 throw SerializationError("unsupported tile count");
1653 for (u32 i = 0; i < 6; i++)
1654 tiledef[i].deSerialize(is, version, drawtype);
1655 if (readU8(is) != CF_SPECIAL_COUNT)
1656 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1657 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1658 tiledef_special[i].deSerialize(is, version, drawtype);
1660 post_effect_color.setAlpha(readU8(is));
1661 post_effect_color.setRed(readU8(is));
1662 post_effect_color.setGreen(readU8(is));
1663 post_effect_color.setBlue(readU8(is));
1664 param_type = (enum ContentParamType)readU8(is);
1665 param_type_2 = (enum ContentParamType2)readU8(is);
1666 is_ground_content = readU8(is);
1667 light_propagates = readU8(is);
1668 sunlight_propagates = readU8(is);
1669 walkable = readU8(is);
1670 pointable = readU8(is);
1671 diggable = readU8(is);
1672 climbable = readU8(is);
1673 buildable_to = readU8(is);
1674 deSerializeString(is); // legacy: used to be metadata_name
1675 liquid_type = (enum LiquidType)readU8(is);
1676 liquid_alternative_flowing = deSerializeString(is);
1677 liquid_alternative_source = deSerializeString(is);
1678 liquid_viscosity = readU8(is);
1679 light_source = readU8(is);
1680 light_source = MYMIN(light_source, LIGHT_MAX);
1681 damage_per_second = readU32(is);
1682 node_box.deSerialize(is);
1683 selection_box.deSerialize(is);
1684 legacy_facedir_simple = readU8(is);
1685 legacy_wallmounted = readU8(is);
1686 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1687 deSerializeSimpleSoundSpec(sound_dig, is, version);
1688 deSerializeSimpleSoundSpec(sound_dug, is, version);
1689 } else if (version == 6) {
1690 name = deSerializeString(is);
1692 u32 groups_size = readU16(is);
1693 for (u32 i = 0; i < groups_size; i++) {
1694 std::string name = deSerializeString(is);
1695 int value = readS16(is);
1696 groups[name] = value;
1698 drawtype = (enum NodeDrawType)readU8(is);
1699 visual_scale = readF1000(is);
1700 if (readU8(is) != 6)
1701 throw SerializationError("unsupported tile count");
1702 for (u32 i = 0; i < 6; i++)
1703 tiledef[i].deSerialize(is, version, drawtype);
1704 // CF_SPECIAL_COUNT in version 6 = 2
1705 if (readU8(is) != 2)
1706 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1707 for (u32 i = 0; i < 2; i++)
1708 tiledef_special[i].deSerialize(is, version, drawtype);
1710 post_effect_color.setAlpha(readU8(is));
1711 post_effect_color.setRed(readU8(is));
1712 post_effect_color.setGreen(readU8(is));
1713 post_effect_color.setBlue(readU8(is));
1714 param_type = (enum ContentParamType)readU8(is);
1715 param_type_2 = (enum ContentParamType2)readU8(is);
1716 is_ground_content = readU8(is);
1717 light_propagates = readU8(is);
1718 sunlight_propagates = readU8(is);
1719 walkable = readU8(is);
1720 pointable = readU8(is);
1721 diggable = readU8(is);
1722 climbable = readU8(is);
1723 buildable_to = readU8(is);
1724 deSerializeString(is); // legacy: used to be metadata_name
1725 liquid_type = (enum LiquidType)readU8(is);
1726 liquid_alternative_flowing = deSerializeString(is);
1727 liquid_alternative_source = deSerializeString(is);
1728 liquid_viscosity = readU8(is);
1729 liquid_renewable = readU8(is);
1730 light_source = readU8(is);
1731 damage_per_second = readU32(is);
1732 node_box.deSerialize(is);
1733 selection_box.deSerialize(is);
1734 legacy_facedir_simple = readU8(is);
1735 legacy_wallmounted = readU8(is);
1736 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1737 deSerializeSimpleSoundSpec(sound_dig, is, version);
1738 deSerializeSimpleSoundSpec(sound_dug, is, version);
1739 rightclickable = readU8(is);
1740 drowning = readU8(is);
1741 leveled = readU8(is);
1742 liquid_range = readU8(is);
1743 } else if (version == 7 || version == 8){
1744 name = deSerializeString(is);
1746 u32 groups_size = readU16(is);
1747 for (u32 i = 0; i < groups_size; i++) {
1748 std::string name = deSerializeString(is);
1749 int value = readS16(is);
1750 groups[name] = value;
1752 drawtype = (enum NodeDrawType) readU8(is);
1754 visual_scale = readF1000(is);
1755 if (readU8(is) != 6)
1756 throw SerializationError("unsupported tile count");
1757 for (u32 i = 0; i < 6; i++)
1758 tiledef[i].deSerialize(is, version, drawtype);
1759 if (readU8(is) != CF_SPECIAL_COUNT)
1760 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1761 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1762 tiledef_special[i].deSerialize(is, version, drawtype);
1764 post_effect_color.setAlpha(readU8(is));
1765 post_effect_color.setRed(readU8(is));
1766 post_effect_color.setGreen(readU8(is));
1767 post_effect_color.setBlue(readU8(is));
1768 param_type = (enum ContentParamType) readU8(is);
1769 param_type_2 = (enum ContentParamType2) readU8(is);
1770 is_ground_content = readU8(is);
1771 light_propagates = readU8(is);
1772 sunlight_propagates = readU8(is);
1773 walkable = readU8(is);
1774 pointable = readU8(is);
1775 diggable = readU8(is);
1776 climbable = readU8(is);
1777 buildable_to = readU8(is);
1778 deSerializeString(is); // legacy: used to be metadata_name
1779 liquid_type = (enum LiquidType) readU8(is);
1780 liquid_alternative_flowing = deSerializeString(is);
1781 liquid_alternative_source = deSerializeString(is);
1782 liquid_viscosity = readU8(is);
1783 liquid_renewable = readU8(is);
1784 light_source = readU8(is);
1785 light_source = MYMIN(light_source, LIGHT_MAX);
1786 damage_per_second = readU32(is);
1787 node_box.deSerialize(is);
1788 selection_box.deSerialize(is);
1789 legacy_facedir_simple = readU8(is);
1790 legacy_wallmounted = readU8(is);
1791 deSerializeSimpleSoundSpec(sound_footstep, is, version);
1792 deSerializeSimpleSoundSpec(sound_dig, is, version);
1793 deSerializeSimpleSoundSpec(sound_dug, is, version);
1794 rightclickable = readU8(is);
1795 drowning = readU8(is);
1796 leveled = readU8(is);
1797 liquid_range = readU8(is);
1798 waving = readU8(is);
1800 mesh = deSerializeString(is);
1801 collision_box.deSerialize(is);
1802 floodable = readU8(is);
1803 u16 connects_to_size = readU16(is);
1804 connects_to_ids.clear();
1805 for (u16 i = 0; i < connects_to_size; i++)
1806 connects_to_ids.insert(readU16(is));
1807 connect_sides = readU8(is);
1808 } catch (SerializationError &e) {};
1810 throw SerializationError("unsupported ContentFeatures version");
1814 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1816 m_node_registration_complete = completed;
1820 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1823 if (m_node_registration_complete)
1824 nr->nodeResolveInternal();
1826 m_pending_resolve_callbacks.push_back(nr);
1830 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1832 size_t len = m_pending_resolve_callbacks.size();
1833 for (size_t i = 0; i != len; i++) {
1834 if (nr != m_pending_resolve_callbacks[i])
1838 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1839 m_pending_resolve_callbacks.resize(len);
1847 void CNodeDefManager::runNodeResolveCallbacks()
1849 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1850 NodeResolver *nr = m_pending_resolve_callbacks[i];
1851 nr->nodeResolveInternal();
1854 m_pending_resolve_callbacks.clear();
1858 void CNodeDefManager::resetNodeResolveState()
1860 m_node_registration_complete = false;
1861 m_pending_resolve_callbacks.clear();
1864 void CNodeDefManager::mapNodeboxConnections()
1866 for (u32 i = 0; i < m_content_features.size(); i++) {
1867 ContentFeatures *f = &m_content_features[i];
1868 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1870 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1871 it != f->connects_to.end(); ++it) {
1872 getIds(*it, f->connects_to_ids);
1877 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1879 const ContentFeatures &f1 = get(from);
1881 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1884 // lookup target in connected set
1885 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1888 const ContentFeatures &f2 = get(to);
1890 if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1891 // ignores actually looking if back connection exists
1892 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1894 // does to node declare usable faces?
1895 if (f2.connect_sides > 0) {
1896 if ((f2.param_type_2 == CPT2_FACEDIR ||
1897 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1898 && (connect_face >= 4)) {
1899 static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1900 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1902 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1904 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
1905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1907 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 32, 16, 8, 4 // 32 - left
1911 return (f2.connect_sides
1912 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1914 return (f2.connect_sides & connect_face);
1916 // the target is just a regular node, so connect no matter back connection
1924 NodeResolver::NodeResolver()
1926 m_nodenames.reserve(16);
1927 m_nnlistsizes.reserve(4);
1931 NodeResolver::~NodeResolver()
1933 if (!m_resolve_done && m_ndef)
1934 m_ndef->cancelNodeResolveCallback(this);
1938 void NodeResolver::nodeResolveInternal()
1940 m_nodenames_idx = 0;
1941 m_nnlistsizes_idx = 0;
1944 m_resolve_done = true;
1946 m_nodenames.clear();
1947 m_nnlistsizes.clear();
1951 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1952 const std::string &node_alt, content_t c_fallback)
1954 if (m_nodenames_idx == m_nodenames.size()) {
1955 *result_out = c_fallback;
1956 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1961 std::string name = m_nodenames[m_nodenames_idx++];
1963 bool success = m_ndef->getId(name, c);
1964 if (!success && node_alt != "") {
1966 success = m_ndef->getId(name, c);
1970 errorstream << "NodeResolver: failed to resolve node name '" << name
1971 << "'." << std::endl;
1980 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1981 bool all_required, content_t c_fallback)
1983 bool success = true;
1985 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1986 errorstream << "NodeResolver: no more node lists" << std::endl;
1990 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1993 if (m_nodenames_idx == m_nodenames.size()) {
1994 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1999 std::string &name = m_nodenames[m_nodenames_idx++];
2001 if (name.substr(0,6) != "group:") {
2002 if (m_ndef->getId(name, c)) {
2003 result_out->push_back(c);
2004 } else if (all_required) {
2005 errorstream << "NodeResolver: failed to resolve node name '"
2006 << name << "'." << std::endl;
2007 result_out->push_back(c_fallback);
2011 std::set<content_t> cids;
2012 std::set<content_t>::iterator it;
2013 m_ndef->getIds(name, cids);
2014 for (it = cids.begin(); it != cids.end(); ++it)
2015 result_out->push_back(*it);