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,
253 os<<serializeString(ss.name);
254 writeF1000(os, ss.gain);
256 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
258 ss.name = deSerializeString(is);
259 ss.gain = readF1000(is);
262 void TextureSettings::readSettings()
264 connected_glass = g_settings->getBool("connected_glass");
265 opaque_water = g_settings->getBool("opaque_water");
266 bool enable_shaders = g_settings->getBool("enable_shaders");
267 bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
268 bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
269 bool smooth_lighting = g_settings->getBool("smooth_lighting");
270 enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
271 enable_minimap = g_settings->getBool("enable_minimap");
272 std::string leaves_style_str = g_settings->get("leaves_style");
274 // Mesh cache is not supported in combination with smooth lighting
276 enable_mesh_cache = false;
278 use_normal_texture = enable_shaders &&
279 (enable_bumpmapping || enable_parallax_occlusion);
280 if (leaves_style_str == "fancy") {
281 leaves_style = LEAVES_FANCY;
282 } else if (leaves_style_str == "simple") {
283 leaves_style = LEAVES_SIMPLE;
285 leaves_style = LEAVES_OPAQUE;
293 ContentFeatures::ContentFeatures()
298 ContentFeatures::~ContentFeatures()
302 void ContentFeatures::reset()
309 visual_solidness = 0;
310 backface_culling = true;
313 has_on_construct = false;
314 has_on_destruct = false;
315 has_after_destruct = false;
319 NOTE: Most of this is always overridden by the default values given
324 // Unknown nodes can be dug
325 groups["dig_immediate"] = 2;
326 drawtype = NDT_NORMAL;
329 for(u32 i = 0; i < 24; i++)
331 minimap_color = video::SColor(0, 0, 0, 0);
334 for(u32 i = 0; i < 6; i++)
335 tiledef[i] = TileDef();
336 for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
337 tiledef_special[j] = TileDef();
339 post_effect_color = video::SColor(0, 0, 0, 0);
340 param_type = CPT_NONE;
341 param_type_2 = CPT2_NONE;
342 is_ground_content = false;
343 light_propagates = false;
344 sunlight_propagates = false;
349 buildable_to = false;
351 rightclickable = true;
353 liquid_type = LIQUID_NONE;
354 liquid_alternative_flowing = "";
355 liquid_alternative_source = "";
356 liquid_viscosity = 0;
357 liquid_renewable = true;
358 liquid_range = LIQUID_LEVEL_MAX+1;
361 damage_per_second = 0;
362 node_box = NodeBox();
363 selection_box = NodeBox();
364 collision_box = NodeBox();
366 legacy_facedir_simple = false;
367 legacy_wallmounted = false;
368 sound_footstep = SimpleSoundSpec();
369 sound_dig = SimpleSoundSpec("__group");
370 sound_dug = SimpleSoundSpec();
372 connects_to_ids.clear();
374 color = video::SColor(0xFFFFFFFF);
379 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
381 if (protocol_version < 31) {
382 serializeOld(os, protocol_version);
390 os << serializeString(name);
391 writeU16(os, groups.size());
392 for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
394 os << serializeString(i->first);
395 writeS16(os, i->second);
397 writeU8(os, param_type);
398 writeU8(os, param_type_2);
401 writeU8(os, drawtype);
402 os << serializeString(mesh);
403 writeF1000(os, visual_scale);
405 for (u32 i = 0; i < 6; i++)
406 tiledef[i].serialize(os, protocol_version);
407 for (u32 i = 0; i < 6; i++)
408 tiledef_overlay[i].serialize(os, protocol_version);
409 writeU8(os, CF_SPECIAL_COUNT);
410 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
411 tiledef_special[i].serialize(os, protocol_version);
414 writeU8(os, color.getRed());
415 writeU8(os, color.getGreen());
416 writeU8(os, color.getBlue());
417 os << serializeString(palette_name);
419 writeU8(os, connect_sides);
420 writeU16(os, connects_to_ids.size());
421 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
422 i != connects_to_ids.end(); ++i)
424 writeU8(os, post_effect_color.getAlpha());
425 writeU8(os, post_effect_color.getRed());
426 writeU8(os, post_effect_color.getGreen());
427 writeU8(os, post_effect_color.getBlue());
428 writeU8(os, leveled);
431 writeU8(os, light_propagates);
432 writeU8(os, sunlight_propagates);
433 writeU8(os, light_source);
436 writeU8(os, is_ground_content);
439 writeU8(os, walkable);
440 writeU8(os, pointable);
441 writeU8(os, diggable);
442 writeU8(os, climbable);
443 writeU8(os, buildable_to);
444 writeU8(os, rightclickable);
445 writeU32(os, damage_per_second);
448 writeU8(os, liquid_type);
449 os << serializeString(liquid_alternative_flowing);
450 os << serializeString(liquid_alternative_source);
451 writeU8(os, liquid_viscosity);
452 writeU8(os, liquid_renewable);
453 writeU8(os, liquid_range);
454 writeU8(os, drowning);
455 writeU8(os, floodable);
458 node_box.serialize(os, protocol_version);
459 selection_box.serialize(os, protocol_version);
460 collision_box.serialize(os, protocol_version);
463 serializeSimpleSoundSpec(sound_footstep, os);
464 serializeSimpleSoundSpec(sound_dig, os);
465 serializeSimpleSoundSpec(sound_dug, os);
468 writeU8(os, legacy_facedir_simple);
469 writeU8(os, legacy_wallmounted);
472 void ContentFeatures::correctAlpha()
474 if (alpha == 0 || alpha == 255)
477 for (u32 i = 0; i < 6; i++) {
479 s << tiledef[i].name << "^[noalpha^[opacity:" << ((int)alpha);
480 tiledef[i].name = s.str();
483 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
485 s << tiledef_special[i].name << "^[noalpha^[opacity:" << ((int)alpha);
486 tiledef_special[i].name = s.str();
490 void ContentFeatures::deSerialize(std::istream &is)
493 int version = readU8(is);
495 deSerializeOld(is, version);
497 } else if (version > 10) {
498 throw SerializationError("unsupported ContentFeatures version");
502 name = deSerializeString(is);
504 u32 groups_size = readU16(is);
505 for (u32 i = 0; i < groups_size; i++) {
506 std::string name = deSerializeString(is);
507 int value = readS16(is);
508 groups[name] = value;
510 param_type = (enum ContentParamType) readU8(is);
511 param_type_2 = (enum ContentParamType2) readU8(is);
514 drawtype = (enum NodeDrawType) readU8(is);
515 mesh = deSerializeString(is);
516 visual_scale = readF1000(is);
518 throw SerializationError("unsupported tile count");
519 for (u32 i = 0; i < 6; i++)
520 tiledef[i].deSerialize(is, version, drawtype);
522 for (u32 i = 0; i < 6; i++)
523 tiledef_overlay[i].deSerialize(is, version, drawtype);
524 if (readU8(is) != CF_SPECIAL_COUNT)
525 throw SerializationError("unsupported CF_SPECIAL_COUNT");
526 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
527 tiledef_special[i].deSerialize(is, version, drawtype);
529 color.setRed(readU8(is));
530 color.setGreen(readU8(is));
531 color.setBlue(readU8(is));
532 palette_name = deSerializeString(is);
534 connect_sides = readU8(is);
535 u16 connects_to_size = readU16(is);
536 connects_to_ids.clear();
537 for (u16 i = 0; i < connects_to_size; i++)
538 connects_to_ids.insert(readU16(is));
539 post_effect_color.setAlpha(readU8(is));
540 post_effect_color.setRed(readU8(is));
541 post_effect_color.setGreen(readU8(is));
542 post_effect_color.setBlue(readU8(is));
543 leveled = readU8(is);
546 light_propagates = readU8(is);
547 sunlight_propagates = readU8(is);
548 light_source = readU8(is);
549 light_source = MYMIN(light_source, LIGHT_MAX);
552 is_ground_content = readU8(is);
555 walkable = readU8(is);
556 pointable = readU8(is);
557 diggable = readU8(is);
558 climbable = readU8(is);
559 buildable_to = readU8(is);
560 rightclickable = readU8(is);
561 damage_per_second = readU32(is);
564 liquid_type = (enum LiquidType) readU8(is);
565 liquid_alternative_flowing = deSerializeString(is);
566 liquid_alternative_source = deSerializeString(is);
567 liquid_viscosity = readU8(is);
568 liquid_renewable = readU8(is);
569 liquid_range = readU8(is);
570 drowning = readU8(is);
571 floodable = readU8(is);
574 node_box.deSerialize(is);
575 selection_box.deSerialize(is);
576 collision_box.deSerialize(is);
579 deSerializeSimpleSoundSpec(sound_footstep, is);
580 deSerializeSimpleSoundSpec(sound_dig, is);
581 deSerializeSimpleSoundSpec(sound_dug, is);
583 // read legacy properties
584 legacy_facedir_simple = readU8(is);
585 legacy_wallmounted = readU8(is);
589 void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *tile,
590 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
591 bool backface_culling, u8 material_type)
593 tile->shader_id = shader_id;
594 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
595 tile->material_type = material_type;
597 // Normal texture and shader flags texture
598 if (use_normal_texture) {
599 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
601 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
604 tile->material_flags = 0;
605 if (backface_culling)
606 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
607 if (tiledef->animation.type != TAT_NONE)
608 tile->material_flags |= MATERIAL_FLAG_ANIMATION;
609 if (tiledef->tileable_horizontal)
610 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
611 if (tiledef->tileable_vertical)
612 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
615 tile->has_color = tiledef->has_color;
616 if (tiledef->has_color)
617 tile->color = tiledef->color;
621 // Animation parameters
623 if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
625 tiledef->animation.determineParams(tile->texture->getOriginalSize(),
626 &frame_count, &frame_length_ms, NULL);
627 tile->animation_frame_count = frame_count;
628 tile->animation_frame_length_ms = frame_length_ms;
631 if (frame_count == 1) {
632 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
634 std::ostringstream os(std::ios::binary);
635 tile->frames.resize(frame_count);
637 for (int i = 0; i < frame_count; i++) {
643 tiledef->animation.getTextureModifer(os,
644 tile->texture->getOriginalSize(), i);
646 frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
647 if (tile->normal_texture)
648 frame.normal_texture = tsrc->getNormalTexture(os.str());
649 frame.flags_texture = tile->flags_texture;
650 tile->frames[i] = frame;
657 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
658 scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
660 // minimap pixel color - the average color of a texture
661 if (tsettings.enable_minimap && tiledef[0].name != "")
662 minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
664 // Figure out the actual tiles to use
666 for (u32 j = 0; j < 6; j++) {
667 tdef[j] = tiledef[j];
668 if (tdef[j].name == "")
669 tdef[j].name = "unknown_node.png";
672 bool is_liquid = false;
673 bool is_water_surface = false;
675 u8 material_type = (alpha == 255) ?
676 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
687 assert(liquid_type == LIQUID_SOURCE);
688 if (tsettings.opaque_water)
693 case NDT_FLOWINGLIQUID:
694 assert(liquid_type == LIQUID_FLOWING);
696 if (tsettings.opaque_water)
702 visual_solidness = 1;
704 case NDT_GLASSLIKE_FRAMED:
706 visual_solidness = 1;
708 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
710 visual_solidness = 1;
711 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
715 visual_solidness = 1;
717 case NDT_ALLFACES_OPTIONAL:
718 if (tsettings.leaves_style == LEAVES_FANCY) {
719 drawtype = NDT_ALLFACES;
721 visual_solidness = 1;
722 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
723 for (u32 j = 0; j < 6; j++) {
724 if (tiledef_special[j].name != "")
725 tdef[j].name = tiledef_special[j].name;
727 drawtype = NDT_GLASSLIKE;
729 visual_solidness = 1;
731 drawtype = NDT_NORMAL;
733 for (u32 i = 0; i < 6; i++)
734 tdef[i].name += std::string("^[noalpha");
737 material_type = TILE_MATERIAL_WAVING_LEAVES;
742 material_type = TILE_MATERIAL_WAVING_PLANTS;
751 material_type = TILE_MATERIAL_WAVING_PLANTS;
752 else if (waving == 2)
753 material_type = TILE_MATERIAL_WAVING_LEAVES;
764 material_type = (alpha == 255) ?
765 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
766 if (name == "default:water_source")
767 is_water_surface = true;
770 // Vertex alpha is no longer supported, correct if necessary.
774 for (u16 j = 0; j < 6; j++) {
775 tile_shader[j] = shdsrc->getShader("nodes_shader",
776 material_type, drawtype);
779 if (is_water_surface) {
780 tile_shader[0] = shdsrc->getShader("water_surface_shader",
781 material_type, drawtype);
784 // Tiles (fill in f->tiles[])
785 for (u16 j = 0; j < 6; j++) {
786 fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
787 tsettings.use_normal_texture,
788 tiledef[j].backface_culling, material_type);
789 if (tiledef_overlay[j].name!="")
790 fillTileAttribs(tsrc, &tiles[j].layers[1], &tiledef_overlay[j],
791 tile_shader[j], tsettings.use_normal_texture,
792 tiledef[j].backface_culling, material_type);
795 // Special tiles (fill in f->special_tiles[])
796 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
797 fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tiledef_special[j],
798 tile_shader[j], tsettings.use_normal_texture,
799 tiledef_special[j].backface_culling, material_type);
802 if (param_type_2 == CPT2_COLOR ||
803 param_type_2 == CPT2_COLORED_FACEDIR ||
804 param_type_2 == CPT2_COLORED_WALLMOUNTED)
805 palette = tsrc->getPalette(palette_name);
807 if ((drawtype == NDT_MESH) && (mesh != "")) {
809 // Read the mesh and apply scale
810 mesh_ptr[0] = client->getMesh(mesh);
812 v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
813 scaleMesh(mesh_ptr[0], scale);
814 recalculateBoundingBox(mesh_ptr[0]);
815 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
817 } else if ((drawtype == NDT_NODEBOX) &&
818 ((node_box.type == NODEBOX_REGULAR) ||
819 (node_box.type == NODEBOX_FIXED)) &&
820 (!node_box.fixed.empty())) {
821 //Convert regular nodebox nodes to meshnodes
822 //Change the drawtype and apply scale
824 mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
825 v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
826 scaleMesh(mesh_ptr[0], scale);
827 recalculateBoundingBox(mesh_ptr[0]);
828 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
831 //Cache 6dfacedir and wallmounted rotated clones of meshes
832 if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
833 (param_type_2 == CPT2_FACEDIR
834 || param_type_2 == CPT2_COLORED_FACEDIR)) {
835 for (u16 j = 1; j < 24; j++) {
836 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
837 rotateMeshBy6dFacedir(mesh_ptr[j], j);
838 recalculateBoundingBox(mesh_ptr[j]);
839 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
841 } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
842 && (param_type_2 == CPT2_WALLMOUNTED ||
843 param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
844 static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
845 for (u16 j = 1; j < 6; j++) {
846 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
847 rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
848 recalculateBoundingBox(mesh_ptr[j]);
849 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
851 rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
852 recalculateBoundingBox(mesh_ptr[0]);
853 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
862 class CNodeDefManager: public IWritableNodeDefManager {
865 virtual ~CNodeDefManager();
867 virtual IWritableNodeDefManager *clone();
868 inline virtual const ContentFeatures& get(content_t c) const;
869 inline virtual const ContentFeatures& get(const MapNode &n) const;
870 virtual bool getId(const std::string &name, content_t &result) const;
871 virtual content_t getId(const std::string &name) const;
872 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
873 virtual const ContentFeatures& get(const std::string &name) const;
874 content_t allocateId();
875 virtual content_t set(const std::string &name, const ContentFeatures &def);
876 virtual content_t allocateDummy(const std::string &name);
877 virtual void removeNode(const std::string &name);
878 virtual void updateAliases(IItemDefManager *idef);
879 virtual void applyTextureOverrides(const std::string &override_filepath);
880 virtual void updateTextures(IGameDef *gamedef,
881 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
882 void *progress_cbk_args);
883 void serialize(std::ostream &os, u16 protocol_version) const;
884 void deSerialize(std::istream &is);
886 inline virtual bool getNodeRegistrationStatus() const;
887 inline virtual void setNodeRegistrationStatus(bool completed);
889 virtual void pendNodeResolve(NodeResolver *nr);
890 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
891 virtual void runNodeResolveCallbacks();
892 virtual void resetNodeResolveState();
893 virtual void mapNodeboxConnections();
894 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
895 virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
897 return m_selection_box_int_union;
901 void addNameIdMapping(content_t i, std::string name);
903 * Recalculates m_selection_box_int_union based on
904 * m_selection_box_union.
906 void fixSelectionBoxIntUnion();
908 // Features indexed by id
909 std::vector<ContentFeatures> m_content_features;
911 // A mapping for fast converting back and forth between names and ids
912 NameIdMapping m_name_id_mapping;
914 // Like m_name_id_mapping, but only from names to ids, and includes
915 // item aliases too. Updated by updateAliases()
916 // Note: Not serialized.
918 UNORDERED_MAP<std::string, content_t> m_name_id_mapping_with_aliases;
920 // A mapping from groups to a list of content_ts (and their levels)
921 // that belong to it. Necessary for a direct lookup in getIds().
922 // Note: Not serialized.
923 UNORDERED_MAP<std::string, GroupItems> m_group_to_items;
925 // Next possibly free id
928 // NodeResolvers to callback once node registration has ended
929 std::vector<NodeResolver *> m_pending_resolve_callbacks;
931 // True when all nodes have been registered
932 bool m_node_registration_complete;
934 //! The union of all nodes' selection boxes.
935 aabb3f m_selection_box_union;
937 * The smallest box in node coordinates that
938 * contains all nodes' selection boxes.
940 core::aabbox3d<s16> m_selection_box_int_union;
944 CNodeDefManager::CNodeDefManager()
950 CNodeDefManager::~CNodeDefManager()
953 for (u32 i = 0; i < m_content_features.size(); i++) {
954 ContentFeatures *f = &m_content_features[i];
955 for (u32 j = 0; j < 24; j++) {
957 f->mesh_ptr[j]->drop();
964 void CNodeDefManager::clear()
966 m_content_features.clear();
967 m_name_id_mapping.clear();
968 m_name_id_mapping_with_aliases.clear();
969 m_group_to_items.clear();
971 m_selection_box_union.reset(0,0,0);
972 m_selection_box_int_union.reset(0,0,0);
974 resetNodeResolveState();
976 u32 initial_length = 0;
977 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
978 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
979 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
980 m_content_features.resize(initial_length);
982 // Set CONTENT_UNKNOWN
986 // Insert directly into containers
987 content_t c = CONTENT_UNKNOWN;
988 m_content_features[c] = f;
989 addNameIdMapping(c, f.name);
996 f.drawtype = NDT_AIRLIKE;
997 f.param_type = CPT_LIGHT;
998 f.light_propagates = true;
999 f.sunlight_propagates = true;
1001 f.pointable = false;
1003 f.buildable_to = true;
1005 f.is_ground_content = true;
1006 // Insert directly into containers
1007 content_t c = CONTENT_AIR;
1008 m_content_features[c] = f;
1009 addNameIdMapping(c, f.name);
1012 // Set CONTENT_IGNORE
1016 f.drawtype = NDT_AIRLIKE;
1017 f.param_type = CPT_NONE;
1018 f.light_propagates = false;
1019 f.sunlight_propagates = false;
1021 f.pointable = false;
1023 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
1024 f.is_ground_content = true;
1025 // Insert directly into containers
1026 content_t c = CONTENT_IGNORE;
1027 m_content_features[c] = f;
1028 addNameIdMapping(c, f.name);
1033 IWritableNodeDefManager *CNodeDefManager::clone()
1035 CNodeDefManager *mgr = new CNodeDefManager();
1041 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
1043 return c < m_content_features.size()
1044 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
1048 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
1050 return get(n.getContent());
1054 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
1056 UNORDERED_MAP<std::string, content_t>::const_iterator
1057 i = m_name_id_mapping_with_aliases.find(name);
1058 if(i == m_name_id_mapping_with_aliases.end())
1065 content_t CNodeDefManager::getId(const std::string &name) const
1067 content_t id = CONTENT_IGNORE;
1073 bool CNodeDefManager::getIds(const std::string &name,
1074 std::set<content_t> &result) const
1076 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
1077 if (name.substr(0,6) != "group:") {
1078 content_t id = CONTENT_IGNORE;
1079 bool exists = getId(name, id);
1084 std::string group = name.substr(6);
1086 UNORDERED_MAP<std::string, GroupItems>::const_iterator
1087 i = m_group_to_items.find(group);
1088 if (i == m_group_to_items.end())
1091 const GroupItems &items = i->second;
1092 for (GroupItems::const_iterator j = items.begin();
1093 j != items.end(); ++j) {
1094 if ((*j).second != 0)
1095 result.insert((*j).first);
1097 //printf("getIds: %dus\n", t.stop());
1102 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
1104 content_t id = CONTENT_UNKNOWN;
1110 // returns CONTENT_IGNORE if no free ID found
1111 content_t CNodeDefManager::allocateId()
1113 for (content_t id = m_next_id;
1114 id >= m_next_id; // overflow?
1116 while (id >= m_content_features.size()) {
1117 m_content_features.push_back(ContentFeatures());
1119 const ContentFeatures &f = m_content_features[id];
1125 // If we arrive here, an overflow occurred in id.
1126 // That means no ID was found
1127 return CONTENT_IGNORE;
1132 * Returns the smallest box that contains all boxes
1133 * in the vector. Box_union is expanded.
1134 * @param[in] boxes the vector containing the boxes
1135 * @param[in, out] box_union the union of the arguments
1137 void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
1139 for (std::vector<aabb3f>::const_iterator it = boxes.begin();
1140 it != boxes.end(); ++it) {
1141 box_union->addInternalBox(*it);
1147 * Returns a box that contains the nodebox in every case.
1148 * The argument node_union is expanded.
1149 * @param[in] nodebox the nodebox to be measured
1150 * @param[in] features used to decide whether the nodebox
1152 * @param[in, out] box_union the union of the arguments
1154 void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
1157 switch(nodebox.type) {
1159 case NODEBOX_LEVELED: {
1161 aabb3f half_processed(0, 0, 0, 0, 0, 0);
1162 boxVectorUnion(nodebox.fixed, &half_processed);
1163 // Set leveled boxes to maximal
1164 if (nodebox.type == NODEBOX_LEVELED) {
1165 half_processed.MaxEdge.Y = +BS / 2;
1167 if (features.param_type_2 == CPT2_FACEDIR ||
1168 features.param_type_2 == CPT2_COLORED_FACEDIR) {
1169 // Get maximal coordinate
1171 fabsf(half_processed.MinEdge.X),
1172 fabsf(half_processed.MinEdge.Y),
1173 fabsf(half_processed.MinEdge.Z),
1174 fabsf(half_processed.MaxEdge.X),
1175 fabsf(half_processed.MaxEdge.Y),
1176 fabsf(half_processed.MaxEdge.Z) };
1178 for (int i = 0; i < 6; i++) {
1179 if (max < coords[i]) {
1183 // Add the union of all possible rotated boxes
1184 box_union->addInternalPoint(-max, -max, -max);
1185 box_union->addInternalPoint(+max, +max, +max);
1187 box_union->addInternalBox(half_processed);
1191 case NODEBOX_WALLMOUNTED: {
1193 box_union->addInternalBox(nodebox.wall_top);
1194 box_union->addInternalBox(nodebox.wall_bottom);
1195 // Find maximal coordinate in the X-Z plane
1197 fabsf(nodebox.wall_side.MinEdge.X),
1198 fabsf(nodebox.wall_side.MinEdge.Z),
1199 fabsf(nodebox.wall_side.MaxEdge.X),
1200 fabsf(nodebox.wall_side.MaxEdge.Z) };
1202 for (int i = 0; i < 4; i++) {
1203 if (max < coords[i]) {
1207 // Add the union of all possible rotated boxes
1208 box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
1209 box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
1212 case NODEBOX_CONNECTED: {
1213 // Add all possible connected boxes
1214 boxVectorUnion(nodebox.fixed, box_union);
1215 boxVectorUnion(nodebox.connect_top, box_union);
1216 boxVectorUnion(nodebox.connect_bottom, box_union);
1217 boxVectorUnion(nodebox.connect_front, box_union);
1218 boxVectorUnion(nodebox.connect_left, box_union);
1219 boxVectorUnion(nodebox.connect_back, box_union);
1220 boxVectorUnion(nodebox.connect_right, box_union);
1225 box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
1226 box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
1232 inline void CNodeDefManager::fixSelectionBoxIntUnion()
1234 m_selection_box_int_union.MinEdge.X = floorf(
1235 m_selection_box_union.MinEdge.X / BS + 0.5f);
1236 m_selection_box_int_union.MinEdge.Y = floorf(
1237 m_selection_box_union.MinEdge.Y / BS + 0.5f);
1238 m_selection_box_int_union.MinEdge.Z = floorf(
1239 m_selection_box_union.MinEdge.Z / BS + 0.5f);
1240 m_selection_box_int_union.MaxEdge.X = ceilf(
1241 m_selection_box_union.MaxEdge.X / BS - 0.5f);
1242 m_selection_box_int_union.MaxEdge.Y = ceilf(
1243 m_selection_box_union.MaxEdge.Y / BS - 0.5f);
1244 m_selection_box_int_union.MaxEdge.Z = ceilf(
1245 m_selection_box_union.MaxEdge.Z / BS - 0.5f);
1249 // IWritableNodeDefManager
1250 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1254 assert(name == def.name);
1256 // Don't allow redefining ignore (but allow air and unknown)
1257 if (name == "ignore") {
1258 warningstream << "NodeDefManager: Ignoring "
1259 "CONTENT_IGNORE redefinition"<<std::endl;
1260 return CONTENT_IGNORE;
1263 content_t id = CONTENT_IGNORE;
1264 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1267 if (id == CONTENT_IGNORE) {
1268 warningstream << "NodeDefManager: Absolute "
1269 "limit reached" << std::endl;
1270 return CONTENT_IGNORE;
1272 assert(id != CONTENT_IGNORE);
1273 addNameIdMapping(id, name);
1275 m_content_features[id] = def;
1276 verbosestream << "NodeDefManager: registering content id \"" << id
1277 << "\": name=\"" << def.name << "\""<<std::endl;
1279 getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
1280 fixSelectionBoxIntUnion();
1281 // Add this content to the list of all groups it belongs to
1282 // FIXME: This should remove a node from groups it no longer
1283 // belongs to when a node is re-registered
1284 for (ItemGroupList::const_iterator i = def.groups.begin();
1285 i != def.groups.end(); ++i) {
1286 std::string group_name = i->first;
1288 UNORDERED_MAP<std::string, GroupItems>::iterator
1289 j = m_group_to_items.find(group_name);
1290 if (j == m_group_to_items.end()) {
1291 m_group_to_items[group_name].push_back(
1292 std::make_pair(id, i->second));
1294 GroupItems &items = j->second;
1295 items.push_back(std::make_pair(id, i->second));
1302 content_t CNodeDefManager::allocateDummy(const std::string &name)
1304 assert(name != ""); // Pre-condition
1307 return set(name, f);
1311 void CNodeDefManager::removeNode(const std::string &name)
1316 // Erase name from name ID mapping
1317 content_t id = CONTENT_IGNORE;
1318 if (m_name_id_mapping.getId(name, id)) {
1319 m_name_id_mapping.eraseName(name);
1320 m_name_id_mapping_with_aliases.erase(name);
1323 // Erase node content from all groups it belongs to
1324 for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
1325 m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
1326 GroupItems &items = iter_groups->second;
1327 for (GroupItems::iterator iter_groupitems = items.begin();
1328 iter_groupitems != items.end();) {
1329 if (iter_groupitems->first == id)
1330 items.erase(iter_groupitems++);
1335 // Check if group is empty
1336 if (items.size() == 0)
1337 m_group_to_items.erase(iter_groups++);
1344 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1346 std::set<std::string> all;
1348 m_name_id_mapping_with_aliases.clear();
1349 for (std::set<std::string>::const_iterator
1350 i = all.begin(); i != all.end(); ++i) {
1351 const std::string &name = *i;
1352 const std::string &convert_to = idef->getAlias(name);
1354 if (m_name_id_mapping.getId(convert_to, id)) {
1355 m_name_id_mapping_with_aliases.insert(
1356 std::make_pair(name, id));
1361 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1363 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1364 "overrides to textures from " << override_filepath << std::endl;
1366 std::ifstream infile(override_filepath.c_str());
1369 while (std::getline(infile, line)) {
1371 if (trim(line) == "")
1373 std::vector<std::string> splitted = str_split(line, ' ');
1374 if (splitted.size() != 3) {
1375 errorstream << override_filepath
1376 << ":" << line_c << " Could not apply texture override \""
1377 << line << "\": Syntax error" << std::endl;
1382 if (!getId(splitted[0], id))
1383 continue; // Ignore unknown node
1385 ContentFeatures &nodedef = m_content_features[id];
1387 if (splitted[1] == "top")
1388 nodedef.tiledef[0].name = splitted[2];
1389 else if (splitted[1] == "bottom")
1390 nodedef.tiledef[1].name = splitted[2];
1391 else if (splitted[1] == "right")
1392 nodedef.tiledef[2].name = splitted[2];
1393 else if (splitted[1] == "left")
1394 nodedef.tiledef[3].name = splitted[2];
1395 else if (splitted[1] == "back")
1396 nodedef.tiledef[4].name = splitted[2];
1397 else if (splitted[1] == "front")
1398 nodedef.tiledef[5].name = splitted[2];
1399 else if (splitted[1] == "all" || splitted[1] == "*")
1400 for (int i = 0; i < 6; i++)
1401 nodedef.tiledef[i].name = splitted[2];
1402 else if (splitted[1] == "sides")
1403 for (int i = 2; i < 6; i++)
1404 nodedef.tiledef[i].name = splitted[2];
1406 errorstream << override_filepath
1407 << ":" << line_c << " Could not apply texture override \""
1408 << line << "\": Unknown node side \""
1409 << splitted[1] << "\"" << std::endl;
1415 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1416 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1417 void *progress_callback_args)
1420 infostream << "CNodeDefManager::updateTextures(): Updating "
1421 "textures in node definitions" << std::endl;
1423 Client *client = (Client *)gamedef;
1424 ITextureSource *tsrc = client->tsrc();
1425 IShaderSource *shdsrc = client->getShaderSource();
1426 scene::ISceneManager* smgr = client->getSceneManager();
1427 scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1428 TextureSettings tsettings;
1429 tsettings.readSettings();
1431 u32 size = m_content_features.size();
1433 for (u32 i = 0; i < size; i++) {
1434 ContentFeatures *f = &(m_content_features[i]);
1435 f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
1436 progress_callback(progress_callback_args, i, size);
1441 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1443 writeU8(os, 1); // version
1445 std::ostringstream os2(std::ios::binary);
1446 for (u32 i = 0; i < m_content_features.size(); i++) {
1447 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1448 || i == CONTENT_UNKNOWN)
1450 const ContentFeatures *f = &m_content_features[i];
1454 // Wrap it in a string to allow different lengths without
1455 // strict version incompatibilities
1456 std::ostringstream wrapper_os(std::ios::binary);
1457 f->serialize(wrapper_os, protocol_version);
1458 os2<<serializeString(wrapper_os.str());
1460 // must not overflow
1461 u16 next = count + 1;
1462 FATAL_ERROR_IF(next < count, "Overflow");
1465 writeU16(os, count);
1466 os << serializeLongString(os2.str());
1470 void CNodeDefManager::deSerialize(std::istream &is)
1473 int version = readU8(is);
1475 throw SerializationError("unsupported NodeDefinitionManager version");
1476 u16 count = readU16(is);
1477 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1479 for (u16 n = 0; n < count; n++) {
1480 u16 i = readU16(is2);
1482 // Read it from the string wrapper
1483 std::string wrapper = deSerializeString(is2);
1484 std::istringstream wrapper_is(wrapper, std::ios::binary);
1485 f.deSerialize(wrapper_is);
1487 // Check error conditions
1488 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1489 warningstream << "NodeDefManager::deSerialize(): "
1490 "not changing builtin node " << i << std::endl;
1494 warningstream << "NodeDefManager::deSerialize(): "
1495 "received empty name" << std::endl;
1501 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1502 warningstream << "NodeDefManager::deSerialize(): "
1503 "already defined with different ID: " << f.name << std::endl;
1507 // All is ok, add node definition with the requested ID
1508 if (i >= m_content_features.size())
1509 m_content_features.resize((u32)(i) + 1);
1510 m_content_features[i] = f;
1511 addNameIdMapping(i, f.name);
1512 verbosestream << "deserialized " << f.name << std::endl;
1514 getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
1515 fixSelectionBoxIntUnion();
1520 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1522 m_name_id_mapping.set(i, name);
1523 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1527 IWritableNodeDefManager *createNodeDefManager()
1529 return new CNodeDefManager();
1533 //// Serialization of old ContentFeatures formats
1534 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1536 u8 compatible_param_type_2 = param_type_2;
1537 if ((protocol_version < 28)
1538 && (compatible_param_type_2 == CPT2_MESHOPTIONS))
1539 compatible_param_type_2 = CPT2_NONE;
1540 else if (protocol_version < 30) {
1541 if (compatible_param_type_2 == CPT2_COLOR)
1542 compatible_param_type_2 = CPT2_NONE;
1543 else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
1544 compatible_param_type_2 = CPT2_FACEDIR;
1545 else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
1546 compatible_param_type_2 = CPT2_WALLMOUNTED;
1549 float compatible_visual_scale = visual_scale;
1550 if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
1551 compatible_visual_scale = sqrt(visual_scale);
1553 TileDef compatible_tiles[6];
1554 for (u8 i = 0; i < 6; i++) {
1555 compatible_tiles[i] = tiledef[i];
1556 if (tiledef_overlay[i].name != "") {
1557 std::stringstream s;
1558 s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
1560 compatible_tiles[i].name = s.str();
1565 if (protocol_version < 31) {
1566 writeU8(os, protocol_version < 27 ? 7 : 8);
1568 os << serializeString(name);
1569 writeU16(os, groups.size());
1570 for (ItemGroupList::const_iterator i = groups.begin();
1571 i != groups.end(); ++i) {
1572 os << serializeString(i->first);
1573 writeS16(os, i->second);
1575 writeU8(os, drawtype);
1576 writeF1000(os, compatible_visual_scale);
1578 for (u32 i = 0; i < 6; i++)
1579 compatible_tiles[i].serialize(os, protocol_version);
1580 writeU8(os, CF_SPECIAL_COUNT);
1581 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1582 tiledef_special[i].serialize(os, protocol_version);
1584 writeU8(os, post_effect_color.getAlpha());
1585 writeU8(os, post_effect_color.getRed());
1586 writeU8(os, post_effect_color.getGreen());
1587 writeU8(os, post_effect_color.getBlue());
1588 writeU8(os, param_type);
1589 writeU8(os, compatible_param_type_2);
1590 writeU8(os, is_ground_content);
1591 writeU8(os, light_propagates);
1592 writeU8(os, sunlight_propagates);
1593 writeU8(os, walkable);
1594 writeU8(os, pointable);
1595 writeU8(os, diggable);
1596 writeU8(os, climbable);
1597 writeU8(os, buildable_to);
1598 os << serializeString(""); // legacy: used to be metadata_name
1599 writeU8(os, liquid_type);
1600 os << serializeString(liquid_alternative_flowing);
1601 os << serializeString(liquid_alternative_source);
1602 writeU8(os, liquid_viscosity);
1603 writeU8(os, liquid_renewable);
1604 writeU8(os, light_source);
1605 writeU32(os, damage_per_second);
1606 node_box.serialize(os, protocol_version);
1607 selection_box.serialize(os, protocol_version);
1608 writeU8(os, legacy_facedir_simple);
1609 writeU8(os, legacy_wallmounted);
1610 serializeSimpleSoundSpec(sound_footstep, os);
1611 serializeSimpleSoundSpec(sound_dig, os);
1612 serializeSimpleSoundSpec(sound_dug, os);
1613 writeU8(os, rightclickable);
1614 writeU8(os, drowning);
1615 writeU8(os, leveled);
1616 writeU8(os, liquid_range);
1617 writeU8(os, waving);
1618 os << serializeString(mesh);
1619 collision_box.serialize(os, protocol_version);
1620 writeU8(os, floodable);
1621 writeU16(os, connects_to_ids.size());
1622 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
1623 i != connects_to_ids.end(); ++i)
1625 writeU8(os, connect_sides);
1627 throw SerializationError("ContentFeatures::serialize(): "
1628 "Unsupported version requested");
1632 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1634 if (version == 5) // In PROTOCOL_VERSION 13
1636 name = deSerializeString(is);
1638 u32 groups_size = readU16(is);
1639 for(u32 i=0; i<groups_size; i++){
1640 std::string name = deSerializeString(is);
1641 int value = readS16(is);
1642 groups[name] = value;
1644 drawtype = (enum NodeDrawType)readU8(is);
1646 visual_scale = readF1000(is);
1647 if (readU8(is) != 6)
1648 throw SerializationError("unsupported tile count");
1649 for (u32 i = 0; i < 6; i++)
1650 tiledef[i].deSerialize(is, version, drawtype);
1651 if (readU8(is) != CF_SPECIAL_COUNT)
1652 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1653 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1654 tiledef_special[i].deSerialize(is, version, drawtype);
1656 post_effect_color.setAlpha(readU8(is));
1657 post_effect_color.setRed(readU8(is));
1658 post_effect_color.setGreen(readU8(is));
1659 post_effect_color.setBlue(readU8(is));
1660 param_type = (enum ContentParamType)readU8(is);
1661 param_type_2 = (enum ContentParamType2)readU8(is);
1662 is_ground_content = readU8(is);
1663 light_propagates = readU8(is);
1664 sunlight_propagates = readU8(is);
1665 walkable = readU8(is);
1666 pointable = readU8(is);
1667 diggable = readU8(is);
1668 climbable = readU8(is);
1669 buildable_to = readU8(is);
1670 deSerializeString(is); // legacy: used to be metadata_name
1671 liquid_type = (enum LiquidType)readU8(is);
1672 liquid_alternative_flowing = deSerializeString(is);
1673 liquid_alternative_source = deSerializeString(is);
1674 liquid_viscosity = readU8(is);
1675 light_source = readU8(is);
1676 light_source = MYMIN(light_source, LIGHT_MAX);
1677 damage_per_second = readU32(is);
1678 node_box.deSerialize(is);
1679 selection_box.deSerialize(is);
1680 legacy_facedir_simple = readU8(is);
1681 legacy_wallmounted = readU8(is);
1682 deSerializeSimpleSoundSpec(sound_footstep, is);
1683 deSerializeSimpleSoundSpec(sound_dig, is);
1684 deSerializeSimpleSoundSpec(sound_dug, is);
1685 } else if (version == 6) {
1686 name = deSerializeString(is);
1688 u32 groups_size = readU16(is);
1689 for (u32 i = 0; i < groups_size; i++) {
1690 std::string name = deSerializeString(is);
1691 int value = readS16(is);
1692 groups[name] = value;
1694 drawtype = (enum NodeDrawType)readU8(is);
1695 visual_scale = readF1000(is);
1696 if (readU8(is) != 6)
1697 throw SerializationError("unsupported tile count");
1698 for (u32 i = 0; i < 6; i++)
1699 tiledef[i].deSerialize(is, version, drawtype);
1700 // CF_SPECIAL_COUNT in version 6 = 2
1701 if (readU8(is) != 2)
1702 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1703 for (u32 i = 0; i < 2; i++)
1704 tiledef_special[i].deSerialize(is, version, drawtype);
1706 post_effect_color.setAlpha(readU8(is));
1707 post_effect_color.setRed(readU8(is));
1708 post_effect_color.setGreen(readU8(is));
1709 post_effect_color.setBlue(readU8(is));
1710 param_type = (enum ContentParamType)readU8(is);
1711 param_type_2 = (enum ContentParamType2)readU8(is);
1712 is_ground_content = readU8(is);
1713 light_propagates = readU8(is);
1714 sunlight_propagates = readU8(is);
1715 walkable = readU8(is);
1716 pointable = readU8(is);
1717 diggable = readU8(is);
1718 climbable = readU8(is);
1719 buildable_to = readU8(is);
1720 deSerializeString(is); // legacy: used to be metadata_name
1721 liquid_type = (enum LiquidType)readU8(is);
1722 liquid_alternative_flowing = deSerializeString(is);
1723 liquid_alternative_source = deSerializeString(is);
1724 liquid_viscosity = readU8(is);
1725 liquid_renewable = readU8(is);
1726 light_source = readU8(is);
1727 damage_per_second = readU32(is);
1728 node_box.deSerialize(is);
1729 selection_box.deSerialize(is);
1730 legacy_facedir_simple = readU8(is);
1731 legacy_wallmounted = readU8(is);
1732 deSerializeSimpleSoundSpec(sound_footstep, is);
1733 deSerializeSimpleSoundSpec(sound_dig, is);
1734 deSerializeSimpleSoundSpec(sound_dug, is);
1735 rightclickable = readU8(is);
1736 drowning = readU8(is);
1737 leveled = readU8(is);
1738 liquid_range = readU8(is);
1739 } else if (version == 7 || version == 8){
1740 name = deSerializeString(is);
1742 u32 groups_size = readU16(is);
1743 for (u32 i = 0; i < groups_size; i++) {
1744 std::string name = deSerializeString(is);
1745 int value = readS16(is);
1746 groups[name] = value;
1748 drawtype = (enum NodeDrawType) readU8(is);
1750 visual_scale = readF1000(is);
1751 if (readU8(is) != 6)
1752 throw SerializationError("unsupported tile count");
1753 for (u32 i = 0; i < 6; i++)
1754 tiledef[i].deSerialize(is, version, drawtype);
1755 if (readU8(is) != CF_SPECIAL_COUNT)
1756 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1757 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1758 tiledef_special[i].deSerialize(is, version, drawtype);
1760 post_effect_color.setAlpha(readU8(is));
1761 post_effect_color.setRed(readU8(is));
1762 post_effect_color.setGreen(readU8(is));
1763 post_effect_color.setBlue(readU8(is));
1764 param_type = (enum ContentParamType) readU8(is);
1765 param_type_2 = (enum ContentParamType2) readU8(is);
1766 is_ground_content = readU8(is);
1767 light_propagates = readU8(is);
1768 sunlight_propagates = readU8(is);
1769 walkable = readU8(is);
1770 pointable = readU8(is);
1771 diggable = readU8(is);
1772 climbable = readU8(is);
1773 buildable_to = readU8(is);
1774 deSerializeString(is); // legacy: used to be metadata_name
1775 liquid_type = (enum LiquidType) readU8(is);
1776 liquid_alternative_flowing = deSerializeString(is);
1777 liquid_alternative_source = deSerializeString(is);
1778 liquid_viscosity = readU8(is);
1779 liquid_renewable = readU8(is);
1780 light_source = readU8(is);
1781 light_source = MYMIN(light_source, LIGHT_MAX);
1782 damage_per_second = readU32(is);
1783 node_box.deSerialize(is);
1784 selection_box.deSerialize(is);
1785 legacy_facedir_simple = readU8(is);
1786 legacy_wallmounted = readU8(is);
1787 deSerializeSimpleSoundSpec(sound_footstep, is);
1788 deSerializeSimpleSoundSpec(sound_dig, is);
1789 deSerializeSimpleSoundSpec(sound_dug, is);
1790 rightclickable = readU8(is);
1791 drowning = readU8(is);
1792 leveled = readU8(is);
1793 liquid_range = readU8(is);
1794 waving = readU8(is);
1796 mesh = deSerializeString(is);
1797 collision_box.deSerialize(is);
1798 floodable = readU8(is);
1799 u16 connects_to_size = readU16(is);
1800 connects_to_ids.clear();
1801 for (u16 i = 0; i < connects_to_size; i++)
1802 connects_to_ids.insert(readU16(is));
1803 connect_sides = readU8(is);
1804 } catch (SerializationError &e) {};
1806 throw SerializationError("unsupported ContentFeatures version");
1811 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1813 return m_node_registration_complete;
1817 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1819 m_node_registration_complete = completed;
1823 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1826 if (m_node_registration_complete)
1827 nr->nodeResolveInternal();
1829 m_pending_resolve_callbacks.push_back(nr);
1833 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1835 size_t len = m_pending_resolve_callbacks.size();
1836 for (size_t i = 0; i != len; i++) {
1837 if (nr != m_pending_resolve_callbacks[i])
1841 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1842 m_pending_resolve_callbacks.resize(len);
1850 void CNodeDefManager::runNodeResolveCallbacks()
1852 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1853 NodeResolver *nr = m_pending_resolve_callbacks[i];
1854 nr->nodeResolveInternal();
1857 m_pending_resolve_callbacks.clear();
1861 void CNodeDefManager::resetNodeResolveState()
1863 m_node_registration_complete = false;
1864 m_pending_resolve_callbacks.clear();
1867 void CNodeDefManager::mapNodeboxConnections()
1869 for (u32 i = 0; i < m_content_features.size(); i++) {
1870 ContentFeatures *f = &m_content_features[i];
1871 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1873 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1874 it != f->connects_to.end(); ++it) {
1875 getIds(*it, f->connects_to_ids);
1880 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1882 const ContentFeatures &f1 = get(from);
1884 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1887 // lookup target in connected set
1888 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1891 const ContentFeatures &f2 = get(to);
1893 if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1894 // ignores actually looking if back connection exists
1895 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1897 // does to node declare usable faces?
1898 if (f2.connect_sides > 0) {
1899 if ((f2.param_type_2 == CPT2_FACEDIR ||
1900 f2.param_type_2 == CPT2_COLORED_FACEDIR)
1901 && (connect_face >= 4)) {
1902 static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1903 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1905 8, 4, 32, 16, 0, 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, 16, 8, 4, 32, 0,
1908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1910 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1911 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1912 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
1914 return (f2.connect_sides
1915 & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
1917 return (f2.connect_sides & connect_face);
1919 // the target is just a regular node, so connect no matter back connection
1927 NodeResolver::NodeResolver()
1930 m_nodenames_idx = 0;
1931 m_nnlistsizes_idx = 0;
1932 m_resolve_done = false;
1934 m_nodenames.reserve(16);
1935 m_nnlistsizes.reserve(4);
1939 NodeResolver::~NodeResolver()
1941 if (!m_resolve_done && m_ndef)
1942 m_ndef->cancelNodeResolveCallback(this);
1946 void NodeResolver::nodeResolveInternal()
1948 m_nodenames_idx = 0;
1949 m_nnlistsizes_idx = 0;
1952 m_resolve_done = true;
1954 m_nodenames.clear();
1955 m_nnlistsizes.clear();
1959 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1960 const std::string &node_alt, content_t c_fallback)
1962 if (m_nodenames_idx == m_nodenames.size()) {
1963 *result_out = c_fallback;
1964 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1969 std::string name = m_nodenames[m_nodenames_idx++];
1971 bool success = m_ndef->getId(name, c);
1972 if (!success && node_alt != "") {
1974 success = m_ndef->getId(name, c);
1978 errorstream << "NodeResolver: failed to resolve node name '" << name
1979 << "'." << std::endl;
1988 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1989 bool all_required, content_t c_fallback)
1991 bool success = true;
1993 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1994 errorstream << "NodeResolver: no more node lists" << std::endl;
1998 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
2001 if (m_nodenames_idx == m_nodenames.size()) {
2002 errorstream << "NodeResolver: no more nodes in list" << std::endl;
2007 std::string &name = m_nodenames[m_nodenames_idx++];
2009 if (name.substr(0,6) != "group:") {
2010 if (m_ndef->getId(name, c)) {
2011 result_out->push_back(c);
2012 } else if (all_required) {
2013 errorstream << "NodeResolver: failed to resolve node name '"
2014 << name << "'." << std::endl;
2015 result_out->push_back(c_fallback);
2019 std::set<content_t> cids;
2020 std::set<content_t>::iterator it;
2021 m_ndef->getIds(name, cids);
2022 for (it = cids.begin(); it != cids.end(); ++it)
2023 result_out->push_back(*it);