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"
26 #include <IMeshManipulator.h>
30 #include "nameidmapping.h"
31 #include "util/numeric.h"
32 #include "util/serialize.h"
33 #include "exceptions.h"
37 #include <fstream> // Used in applyTextureOverrides()
45 type = NODEBOX_REGULAR;
48 // default is sign/ladder-like
49 wall_top = aabb3f(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2);
50 wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2);
51 wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2);
52 // no default for other parts
54 connect_bottom.clear();
55 connect_front.clear();
58 connect_right.clear();
61 void NodeBox::serialize(std::ostream &os, u16 protocol_version) const
64 if (protocol_version >= 27)
66 else if (protocol_version >= 21)
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 >= 26)
193 else if (protocol_version >= 17)
197 os<<serializeString(name);
198 writeU8(os, animation.type);
199 writeU16(os, animation.aspect_w);
200 writeU16(os, animation.aspect_h);
201 writeF1000(os, animation.length);
202 if (protocol_version >= 17)
203 writeU8(os, backface_culling);
204 if (protocol_version >= 26) {
205 writeU8(os, tileable_horizontal);
206 writeU8(os, tileable_vertical);
210 void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
212 int version = readU8(is);
213 name = deSerializeString(is);
214 animation.type = (TileAnimationType)readU8(is);
215 animation.aspect_w = readU16(is);
216 animation.aspect_h = readU16(is);
217 animation.length = readF1000(is);
219 backface_culling = readU8(is);
221 tileable_horizontal = readU8(is);
222 tileable_vertical = readU8(is);
225 if ((contenfeatures_version < 8) &&
226 ((drawtype == NDT_MESH) ||
227 (drawtype == NDT_FIRELIKE) ||
228 (drawtype == NDT_LIQUID) ||
229 (drawtype == NDT_PLANTLIKE)))
230 backface_culling = false;
235 SimpleSoundSpec serialization
238 static void serializeSimpleSoundSpec(const SimpleSoundSpec &ss,
241 os<<serializeString(ss.name);
242 writeF1000(os, ss.gain);
244 static void deSerializeSimpleSoundSpec(SimpleSoundSpec &ss, std::istream &is)
246 ss.name = deSerializeString(is);
247 ss.gain = readF1000(is);
250 void TextureSettings::readSettings()
252 connected_glass = g_settings->getBool("connected_glass");
253 opaque_water = g_settings->getBool("opaque_water");
254 bool enable_shaders = g_settings->getBool("enable_shaders");
255 bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
256 bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
257 enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
258 enable_minimap = g_settings->getBool("enable_minimap");
259 std::string leaves_style_str = g_settings->get("leaves_style");
261 use_normal_texture = enable_shaders &&
262 (enable_bumpmapping || enable_parallax_occlusion);
263 if (leaves_style_str == "fancy") {
264 leaves_style = LEAVES_FANCY;
265 } else if (leaves_style_str == "simple") {
266 leaves_style = LEAVES_SIMPLE;
268 leaves_style = LEAVES_OPAQUE;
276 ContentFeatures::ContentFeatures()
281 ContentFeatures::~ContentFeatures()
285 void ContentFeatures::reset()
292 visual_solidness = 0;
293 backface_culling = true;
296 has_on_construct = false;
297 has_on_destruct = false;
298 has_after_destruct = false;
302 NOTE: Most of this is always overridden by the default values given
307 // Unknown nodes can be dug
308 groups["dig_immediate"] = 2;
309 drawtype = NDT_NORMAL;
312 for(u32 i = 0; i < 24; i++)
314 minimap_color = video::SColor(0, 0, 0, 0);
317 for(u32 i = 0; i < 6; i++)
318 tiledef[i] = TileDef();
319 for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
320 tiledef_special[j] = TileDef();
322 post_effect_color = video::SColor(0, 0, 0, 0);
323 param_type = CPT_NONE;
324 param_type_2 = CPT2_NONE;
325 is_ground_content = false;
326 light_propagates = false;
327 sunlight_propagates = false;
332 buildable_to = false;
334 rightclickable = true;
336 liquid_type = LIQUID_NONE;
337 liquid_alternative_flowing = "";
338 liquid_alternative_source = "";
339 liquid_viscosity = 0;
340 liquid_renewable = true;
341 liquid_range = LIQUID_LEVEL_MAX+1;
344 damage_per_second = 0;
345 node_box = NodeBox();
346 selection_box = NodeBox();
347 collision_box = NodeBox();
349 legacy_facedir_simple = false;
350 legacy_wallmounted = false;
351 sound_footstep = SimpleSoundSpec();
352 sound_dig = SimpleSoundSpec("__group");
353 sound_dug = SimpleSoundSpec();
355 connects_to_ids.clear();
359 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
361 if(protocol_version < 24){
362 serializeOld(os, protocol_version);
366 writeU8(os, protocol_version < 27 ? 7 : 8);
368 os<<serializeString(name);
369 writeU16(os, groups.size());
370 for(ItemGroupList::const_iterator
371 i = groups.begin(); i != groups.end(); ++i){
372 os<<serializeString(i->first);
373 writeS16(os, i->second);
375 writeU8(os, drawtype);
376 writeF1000(os, visual_scale);
378 for(u32 i = 0; i < 6; i++)
379 tiledef[i].serialize(os, protocol_version);
380 writeU8(os, CF_SPECIAL_COUNT);
381 for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
382 tiledef_special[i].serialize(os, protocol_version);
385 writeU8(os, post_effect_color.getAlpha());
386 writeU8(os, post_effect_color.getRed());
387 writeU8(os, post_effect_color.getGreen());
388 writeU8(os, post_effect_color.getBlue());
389 writeU8(os, param_type);
390 if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS))
391 writeU8(os, CPT2_NONE);
393 writeU8(os, param_type_2);
394 writeU8(os, is_ground_content);
395 writeU8(os, light_propagates);
396 writeU8(os, sunlight_propagates);
397 writeU8(os, walkable);
398 writeU8(os, pointable);
399 writeU8(os, diggable);
400 writeU8(os, climbable);
401 writeU8(os, buildable_to);
402 os<<serializeString(""); // legacy: used to be metadata_name
403 writeU8(os, liquid_type);
404 os<<serializeString(liquid_alternative_flowing);
405 os<<serializeString(liquid_alternative_source);
406 writeU8(os, liquid_viscosity);
407 writeU8(os, liquid_renewable);
408 writeU8(os, light_source);
409 writeU32(os, damage_per_second);
410 node_box.serialize(os, protocol_version);
411 selection_box.serialize(os, protocol_version);
412 writeU8(os, legacy_facedir_simple);
413 writeU8(os, legacy_wallmounted);
414 serializeSimpleSoundSpec(sound_footstep, os);
415 serializeSimpleSoundSpec(sound_dig, os);
416 serializeSimpleSoundSpec(sound_dug, os);
417 writeU8(os, rightclickable);
418 writeU8(os, drowning);
419 writeU8(os, leveled);
420 writeU8(os, liquid_range);
422 // Stuff below should be moved to correct place in a version that otherwise changes
423 // the protocol version
424 os<<serializeString(mesh);
425 collision_box.serialize(os, protocol_version);
426 writeU8(os, floodable);
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, connect_sides);
434 void ContentFeatures::deSerialize(std::istream &is)
436 int version = readU8(is);
438 deSerializeOld(is, version);
440 } else if (version > 8) {
441 throw SerializationError("unsupported ContentFeatures version");
444 name = deSerializeString(is);
446 u32 groups_size = readU16(is);
447 for(u32 i = 0; i < groups_size; i++){
448 std::string name = deSerializeString(is);
449 int value = readS16(is);
450 groups[name] = value;
452 drawtype = (enum NodeDrawType)readU8(is);
454 visual_scale = readF1000(is);
456 throw SerializationError("unsupported tile count");
457 for(u32 i = 0; i < 6; i++)
458 tiledef[i].deSerialize(is, version, drawtype);
459 if(readU8(is) != CF_SPECIAL_COUNT)
460 throw SerializationError("unsupported CF_SPECIAL_COUNT");
461 for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
462 tiledef_special[i].deSerialize(is, version, drawtype);
464 post_effect_color.setAlpha(readU8(is));
465 post_effect_color.setRed(readU8(is));
466 post_effect_color.setGreen(readU8(is));
467 post_effect_color.setBlue(readU8(is));
468 param_type = (enum ContentParamType)readU8(is);
469 param_type_2 = (enum ContentParamType2)readU8(is);
470 is_ground_content = readU8(is);
471 light_propagates = readU8(is);
472 sunlight_propagates = readU8(is);
473 walkable = readU8(is);
474 pointable = readU8(is);
475 diggable = readU8(is);
476 climbable = readU8(is);
477 buildable_to = readU8(is);
478 deSerializeString(is); // legacy: used to be metadata_name
479 liquid_type = (enum LiquidType)readU8(is);
480 liquid_alternative_flowing = deSerializeString(is);
481 liquid_alternative_source = deSerializeString(is);
482 liquid_viscosity = readU8(is);
483 liquid_renewable = readU8(is);
484 light_source = readU8(is);
485 light_source = MYMIN(light_source, LIGHT_MAX);
486 damage_per_second = readU32(is);
487 node_box.deSerialize(is);
488 selection_box.deSerialize(is);
489 legacy_facedir_simple = readU8(is);
490 legacy_wallmounted = readU8(is);
491 deSerializeSimpleSoundSpec(sound_footstep, is);
492 deSerializeSimpleSoundSpec(sound_dig, is);
493 deSerializeSimpleSoundSpec(sound_dug, is);
494 rightclickable = readU8(is);
495 drowning = readU8(is);
496 leveled = readU8(is);
497 liquid_range = readU8(is);
499 // If you add anything here, insert it primarily inside the try-catch
500 // block to not need to increase the version.
502 // Stuff below should be moved to correct place in a version that
503 // otherwise changes the protocol version
504 mesh = deSerializeString(is);
505 collision_box.deSerialize(is);
506 floodable = readU8(is);
507 u16 connects_to_size = readU16(is);
508 connects_to_ids.clear();
509 for (u16 i = 0; i < connects_to_size; i++)
510 connects_to_ids.insert(readU16(is));
511 connect_sides = readU8(is);
512 }catch(SerializationError &e) {};
516 void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
517 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
518 bool backface_culling, u8 alpha, u8 material_type)
520 tile->shader_id = shader_id;
521 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
523 tile->material_type = material_type;
525 // Normal texture and shader flags texture
526 if (use_normal_texture) {
527 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
529 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
532 tile->material_flags = 0;
533 if (backface_culling)
534 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
535 if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
536 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
537 if (tiledef->tileable_horizontal)
538 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
539 if (tiledef->tileable_vertical)
540 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
542 // Animation parameters
544 if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
545 // Get texture size to determine frame count by aspect ratio
546 v2u32 size = tile->texture->getOriginalSize();
547 int frame_height = (float)size.X /
548 (float)tiledef->animation.aspect_w *
549 (float)tiledef->animation.aspect_h;
550 frame_count = size.Y / frame_height;
551 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
552 tile->animation_frame_count = frame_count;
553 tile->animation_frame_length_ms = frame_length_ms;
556 if (frame_count == 1) {
557 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
559 std::ostringstream os(std::ios::binary);
560 tile->frames.resize(frame_count);
562 for (int i = 0; i < frame_count; i++) {
567 os << tiledef->name << "^[verticalframe:"
568 << frame_count << ":" << i;
570 frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
571 if (tile->normal_texture)
572 frame.normal_texture = tsrc->getNormalTexture(os.str());
573 frame.flags_texture = tile->flags_texture;
574 tile->frames[i] = frame;
581 void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
582 scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip,
583 IGameDef *gamedef, const TextureSettings &tsettings)
585 // minimap pixel color - the average color of a texture
586 if (tsettings.enable_minimap && tiledef[0].name != "")
587 minimap_color = tsrc->getTextureAverageColor(tiledef[0].name);
589 // Figure out the actual tiles to use
591 for (u32 j = 0; j < 6; j++) {
592 tdef[j] = tiledef[j];
593 if (tdef[j].name == "")
594 tdef[j].name = "unknown_node.png";
597 bool is_liquid = false;
598 bool is_water_surface = false;
600 u8 material_type = (alpha == 255) ?
601 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
612 assert(liquid_type == LIQUID_SOURCE);
613 if (tsettings.opaque_water)
618 case NDT_FLOWINGLIQUID:
619 assert(liquid_type == LIQUID_FLOWING);
621 if (tsettings.opaque_water)
627 visual_solidness = 1;
629 case NDT_GLASSLIKE_FRAMED:
631 visual_solidness = 1;
633 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
635 visual_solidness = 1;
636 drawtype = tsettings.connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
640 visual_solidness = 1;
642 case NDT_ALLFACES_OPTIONAL:
643 if (tsettings.leaves_style == LEAVES_FANCY) {
644 drawtype = NDT_ALLFACES;
646 visual_solidness = 1;
647 } else if (tsettings.leaves_style == LEAVES_SIMPLE) {
648 for (u32 j = 0; j < 6; j++) {
649 if (tiledef_special[j].name != "")
650 tdef[j].name = tiledef_special[j].name;
652 drawtype = NDT_GLASSLIKE;
654 visual_solidness = 1;
656 drawtype = NDT_NORMAL;
658 for (u32 i = 0; i < 6; i++)
659 tdef[i].name += std::string("^[noalpha");
662 material_type = TILE_MATERIAL_WAVING_LEAVES;
667 material_type = TILE_MATERIAL_WAVING_PLANTS;
685 material_type = (alpha == 255) ?
686 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
687 if (name == "default:water_source")
688 is_water_surface = true;
692 for (u16 j = 0; j < 6; j++) {
693 tile_shader[j] = shdsrc->getShader("nodes_shader",
694 material_type, drawtype);
697 if (is_water_surface) {
698 tile_shader[0] = shdsrc->getShader("water_surface_shader",
699 material_type, drawtype);
702 // Tiles (fill in f->tiles[])
703 for (u16 j = 0; j < 6; j++) {
704 fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j],
705 tsettings.use_normal_texture,
706 tiledef[j].backface_culling, alpha, material_type);
709 // Special tiles (fill in f->special_tiles[])
710 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
711 fillTileAttribs(tsrc, &special_tiles[j], &tiledef_special[j],
712 tile_shader[j], tsettings.use_normal_texture,
713 tiledef_special[j].backface_culling, alpha, material_type);
716 if ((drawtype == NDT_MESH) && (mesh != "")) {
718 // Read the mesh and apply scale
719 mesh_ptr[0] = gamedef->getMesh(mesh);
721 v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
722 scaleMesh(mesh_ptr[0], scale);
723 recalculateBoundingBox(mesh_ptr[0]);
724 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
726 } else if ((drawtype == NDT_NODEBOX) &&
727 ((node_box.type == NODEBOX_REGULAR) ||
728 (node_box.type == NODEBOX_FIXED)) &&
729 (!node_box.fixed.empty())) {
730 //Convert regular nodebox nodes to meshnodes
731 //Change the drawtype and apply scale
733 mesh_ptr[0] = convertNodeboxesToMesh(node_box.fixed);
734 v3f scale = v3f(1.0, 1.0, 1.0) * visual_scale;
735 scaleMesh(mesh_ptr[0], scale);
736 recalculateBoundingBox(mesh_ptr[0]);
737 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
740 //Cache 6dfacedir and wallmounted rotated clones of meshes
741 if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR)) {
742 for (u16 j = 1; j < 24; j++) {
743 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
744 rotateMeshBy6dFacedir(mesh_ptr[j], j);
745 recalculateBoundingBox(mesh_ptr[j]);
746 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
748 } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED)) {
749 static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
750 for (u16 j = 1; j < 6; j++) {
751 mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
752 rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
753 recalculateBoundingBox(mesh_ptr[j]);
754 meshmanip->recalculateNormals(mesh_ptr[j], true, false);
756 rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]);
757 recalculateBoundingBox(mesh_ptr[0]);
758 meshmanip->recalculateNormals(mesh_ptr[0], true, false);
767 class CNodeDefManager: public IWritableNodeDefManager {
770 virtual ~CNodeDefManager();
772 virtual IWritableNodeDefManager *clone();
773 inline virtual const ContentFeatures& get(content_t c) const;
774 inline virtual const ContentFeatures& get(const MapNode &n) const;
775 virtual bool getId(const std::string &name, content_t &result) const;
776 virtual content_t getId(const std::string &name) const;
777 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
778 virtual const ContentFeatures& get(const std::string &name) const;
779 content_t allocateId();
780 virtual content_t set(const std::string &name, const ContentFeatures &def);
781 virtual content_t allocateDummy(const std::string &name);
782 virtual void removeNode(const std::string &name);
783 virtual void updateAliases(IItemDefManager *idef);
784 virtual void applyTextureOverrides(const std::string &override_filepath);
785 virtual void updateTextures(IGameDef *gamedef,
786 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
787 void *progress_cbk_args);
788 void serialize(std::ostream &os, u16 protocol_version) const;
789 void deSerialize(std::istream &is);
791 inline virtual bool getNodeRegistrationStatus() const;
792 inline virtual void setNodeRegistrationStatus(bool completed);
794 virtual void pendNodeResolve(NodeResolver *nr);
795 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
796 virtual void runNodeResolveCallbacks();
797 virtual void resetNodeResolveState();
798 virtual void mapNodeboxConnections();
799 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
802 void addNameIdMapping(content_t i, std::string name);
804 // Features indexed by id
805 std::vector<ContentFeatures> m_content_features;
807 // A mapping for fast converting back and forth between names and ids
808 NameIdMapping m_name_id_mapping;
810 // Like m_name_id_mapping, but only from names to ids, and includes
811 // item aliases too. Updated by updateAliases()
812 // Note: Not serialized.
814 UNORDERED_MAP<std::string, content_t> m_name_id_mapping_with_aliases;
816 // A mapping from groups to a list of content_ts (and their levels)
817 // that belong to it. Necessary for a direct lookup in getIds().
818 // Note: Not serialized.
819 UNORDERED_MAP<std::string, GroupItems> m_group_to_items;
821 // Next possibly free id
824 // NodeResolvers to callback once node registration has ended
825 std::vector<NodeResolver *> m_pending_resolve_callbacks;
827 // True when all nodes have been registered
828 bool m_node_registration_complete;
832 CNodeDefManager::CNodeDefManager()
838 CNodeDefManager::~CNodeDefManager()
841 for (u32 i = 0; i < m_content_features.size(); i++) {
842 ContentFeatures *f = &m_content_features[i];
843 for (u32 j = 0; j < 24; j++) {
845 f->mesh_ptr[j]->drop();
852 void CNodeDefManager::clear()
854 m_content_features.clear();
855 m_name_id_mapping.clear();
856 m_name_id_mapping_with_aliases.clear();
857 m_group_to_items.clear();
860 resetNodeResolveState();
862 u32 initial_length = 0;
863 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
864 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
865 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
866 m_content_features.resize(initial_length);
868 // Set CONTENT_UNKNOWN
872 // Insert directly into containers
873 content_t c = CONTENT_UNKNOWN;
874 m_content_features[c] = f;
875 addNameIdMapping(c, f.name);
882 f.drawtype = NDT_AIRLIKE;
883 f.param_type = CPT_LIGHT;
884 f.light_propagates = true;
885 f.sunlight_propagates = true;
889 f.buildable_to = true;
891 f.is_ground_content = true;
892 // Insert directly into containers
893 content_t c = CONTENT_AIR;
894 m_content_features[c] = f;
895 addNameIdMapping(c, f.name);
898 // Set CONTENT_IGNORE
902 f.drawtype = NDT_AIRLIKE;
903 f.param_type = CPT_NONE;
904 f.light_propagates = false;
905 f.sunlight_propagates = false;
909 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
910 f.is_ground_content = true;
911 // Insert directly into containers
912 content_t c = CONTENT_IGNORE;
913 m_content_features[c] = f;
914 addNameIdMapping(c, f.name);
919 IWritableNodeDefManager *CNodeDefManager::clone()
921 CNodeDefManager *mgr = new CNodeDefManager();
927 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
929 return c < m_content_features.size()
930 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
934 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
936 return get(n.getContent());
940 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
942 UNORDERED_MAP<std::string, content_t>::const_iterator
943 i = m_name_id_mapping_with_aliases.find(name);
944 if(i == m_name_id_mapping_with_aliases.end())
951 content_t CNodeDefManager::getId(const std::string &name) const
953 content_t id = CONTENT_IGNORE;
959 bool CNodeDefManager::getIds(const std::string &name,
960 std::set<content_t> &result) const
962 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
963 if (name.substr(0,6) != "group:") {
964 content_t id = CONTENT_IGNORE;
965 bool exists = getId(name, id);
970 std::string group = name.substr(6);
972 UNORDERED_MAP<std::string, GroupItems>::const_iterator
973 i = m_group_to_items.find(group);
974 if (i == m_group_to_items.end())
977 const GroupItems &items = i->second;
978 for (GroupItems::const_iterator j = items.begin();
979 j != items.end(); ++j) {
980 if ((*j).second != 0)
981 result.insert((*j).first);
983 //printf("getIds: %dus\n", t.stop());
988 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
990 content_t id = CONTENT_UNKNOWN;
996 // returns CONTENT_IGNORE if no free ID found
997 content_t CNodeDefManager::allocateId()
999 for (content_t id = m_next_id;
1000 id >= m_next_id; // overflow?
1002 while (id >= m_content_features.size()) {
1003 m_content_features.push_back(ContentFeatures());
1005 const ContentFeatures &f = m_content_features[id];
1011 // If we arrive here, an overflow occurred in id.
1012 // That means no ID was found
1013 return CONTENT_IGNORE;
1017 // IWritableNodeDefManager
1018 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
1022 assert(name == def.name);
1024 // Don't allow redefining ignore (but allow air and unknown)
1025 if (name == "ignore") {
1026 warningstream << "NodeDefManager: Ignoring "
1027 "CONTENT_IGNORE redefinition"<<std::endl;
1028 return CONTENT_IGNORE;
1031 content_t id = CONTENT_IGNORE;
1032 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
1035 if (id == CONTENT_IGNORE) {
1036 warningstream << "NodeDefManager: Absolute "
1037 "limit reached" << std::endl;
1038 return CONTENT_IGNORE;
1040 assert(id != CONTENT_IGNORE);
1041 addNameIdMapping(id, name);
1043 m_content_features[id] = def;
1044 verbosestream << "NodeDefManager: registering content id \"" << id
1045 << "\": name=\"" << def.name << "\""<<std::endl;
1047 // Add this content to the list of all groups it belongs to
1048 // FIXME: This should remove a node from groups it no longer
1049 // belongs to when a node is re-registered
1050 for (ItemGroupList::const_iterator i = def.groups.begin();
1051 i != def.groups.end(); ++i) {
1052 std::string group_name = i->first;
1054 UNORDERED_MAP<std::string, GroupItems>::iterator
1055 j = m_group_to_items.find(group_name);
1056 if (j == m_group_to_items.end()) {
1057 m_group_to_items[group_name].push_back(
1058 std::make_pair(id, i->second));
1060 GroupItems &items = j->second;
1061 items.push_back(std::make_pair(id, i->second));
1068 content_t CNodeDefManager::allocateDummy(const std::string &name)
1070 assert(name != ""); // Pre-condition
1073 return set(name, f);
1077 void CNodeDefManager::removeNode(const std::string &name)
1082 // Erase name from name ID mapping
1083 content_t id = CONTENT_IGNORE;
1084 if (m_name_id_mapping.getId(name, id)) {
1085 m_name_id_mapping.eraseName(name);
1086 m_name_id_mapping_with_aliases.erase(name);
1089 // Erase node content from all groups it belongs to
1090 for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
1091 m_group_to_items.begin();
1092 iter_groups != m_group_to_items.end();) {
1093 GroupItems &items = iter_groups->second;
1094 for (GroupItems::iterator iter_groupitems = items.begin();
1095 iter_groupitems != items.end();) {
1096 if (iter_groupitems->first == id)
1097 items.erase(iter_groupitems++);
1102 // Check if group is empty
1103 if (items.size() == 0)
1104 m_group_to_items.erase(iter_groups++);
1111 void CNodeDefManager::updateAliases(IItemDefManager *idef)
1113 std::set<std::string> all = idef->getAll();
1114 m_name_id_mapping_with_aliases.clear();
1115 for (std::set<std::string>::iterator
1116 i = all.begin(); i != all.end(); ++i) {
1117 std::string name = *i;
1118 std::string convert_to = idef->getAlias(name);
1120 if (m_name_id_mapping.getId(convert_to, id)) {
1121 m_name_id_mapping_with_aliases.insert(
1122 std::make_pair(name, id));
1127 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1129 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
1130 "overrides to textures from " << override_filepath << std::endl;
1132 std::ifstream infile(override_filepath.c_str());
1135 while (std::getline(infile, line)) {
1137 if (trim(line) == "")
1139 std::vector<std::string> splitted = str_split(line, ' ');
1140 if (splitted.size() != 3) {
1141 errorstream << override_filepath
1142 << ":" << line_c << " Could not apply texture override \""
1143 << line << "\": Syntax error" << std::endl;
1148 if (!getId(splitted[0], id))
1149 continue; // Ignore unknown node
1151 ContentFeatures &nodedef = m_content_features[id];
1153 if (splitted[1] == "top")
1154 nodedef.tiledef[0].name = splitted[2];
1155 else if (splitted[1] == "bottom")
1156 nodedef.tiledef[1].name = splitted[2];
1157 else if (splitted[1] == "right")
1158 nodedef.tiledef[2].name = splitted[2];
1159 else if (splitted[1] == "left")
1160 nodedef.tiledef[3].name = splitted[2];
1161 else if (splitted[1] == "back")
1162 nodedef.tiledef[4].name = splitted[2];
1163 else if (splitted[1] == "front")
1164 nodedef.tiledef[5].name = splitted[2];
1165 else if (splitted[1] == "all" || splitted[1] == "*")
1166 for (int i = 0; i < 6; i++)
1167 nodedef.tiledef[i].name = splitted[2];
1168 else if (splitted[1] == "sides")
1169 for (int i = 2; i < 6; i++)
1170 nodedef.tiledef[i].name = splitted[2];
1172 errorstream << override_filepath
1173 << ":" << line_c << " Could not apply texture override \""
1174 << line << "\": Unknown node side \""
1175 << splitted[1] << "\"" << std::endl;
1181 void CNodeDefManager::updateTextures(IGameDef *gamedef,
1182 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
1183 void *progress_callback_args)
1186 infostream << "CNodeDefManager::updateTextures(): Updating "
1187 "textures in node definitions" << std::endl;
1188 ITextureSource *tsrc = gamedef->tsrc();
1189 IShaderSource *shdsrc = gamedef->getShaderSource();
1190 scene::ISceneManager* smgr = gamedef->getSceneManager();
1191 scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
1192 TextureSettings tsettings;
1193 tsettings.readSettings();
1195 u32 size = m_content_features.size();
1197 for (u32 i = 0; i < size; i++) {
1198 m_content_features[i].updateTextures(tsrc, shdsrc, smgr, meshmanip, gamedef, tsettings);
1199 progress_callback(progress_callback_args, i, size);
1204 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1206 writeU8(os, 1); // version
1208 std::ostringstream os2(std::ios::binary);
1209 for (u32 i = 0; i < m_content_features.size(); i++) {
1210 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1211 || i == CONTENT_UNKNOWN)
1213 const ContentFeatures *f = &m_content_features[i];
1217 // Wrap it in a string to allow different lengths without
1218 // strict version incompatibilities
1219 std::ostringstream wrapper_os(std::ios::binary);
1220 f->serialize(wrapper_os, protocol_version);
1221 os2<<serializeString(wrapper_os.str());
1223 // must not overflow
1224 u16 next = count + 1;
1225 FATAL_ERROR_IF(next < count, "Overflow");
1228 writeU16(os, count);
1229 os << serializeLongString(os2.str());
1233 void CNodeDefManager::deSerialize(std::istream &is)
1236 int version = readU8(is);
1238 throw SerializationError("unsupported NodeDefinitionManager version");
1239 u16 count = readU16(is);
1240 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1242 for (u16 n = 0; n < count; n++) {
1243 u16 i = readU16(is2);
1245 // Read it from the string wrapper
1246 std::string wrapper = deSerializeString(is2);
1247 std::istringstream wrapper_is(wrapper, std::ios::binary);
1248 f.deSerialize(wrapper_is);
1250 // Check error conditions
1251 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1252 warningstream << "NodeDefManager::deSerialize(): "
1253 "not changing builtin node " << i << std::endl;
1257 warningstream << "NodeDefManager::deSerialize(): "
1258 "received empty name" << std::endl;
1264 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1265 warningstream << "NodeDefManager::deSerialize(): "
1266 "already defined with different ID: " << f.name << std::endl;
1270 // All is ok, add node definition with the requested ID
1271 if (i >= m_content_features.size())
1272 m_content_features.resize((u32)(i) + 1);
1273 m_content_features[i] = f;
1274 addNameIdMapping(i, f.name);
1275 verbosestream << "deserialized " << f.name << std::endl;
1280 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1282 m_name_id_mapping.set(i, name);
1283 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1287 IWritableNodeDefManager *createNodeDefManager()
1289 return new CNodeDefManager();
1293 //// Serialization of old ContentFeatures formats
1294 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1296 if (protocol_version == 13)
1298 writeU8(os, 5); // version
1299 os<<serializeString(name);
1300 writeU16(os, groups.size());
1301 for (ItemGroupList::const_iterator
1302 i = groups.begin(); i != groups.end(); ++i) {
1303 os<<serializeString(i->first);
1304 writeS16(os, i->second);
1306 writeU8(os, drawtype);
1307 writeF1000(os, visual_scale);
1309 for (u32 i = 0; i < 6; i++)
1310 tiledef[i].serialize(os, protocol_version);
1311 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1313 for (u32 i = 0; i < 2; i++)
1314 tiledef_special[i].serialize(os, protocol_version);
1316 writeU8(os, post_effect_color.getAlpha());
1317 writeU8(os, post_effect_color.getRed());
1318 writeU8(os, post_effect_color.getGreen());
1319 writeU8(os, post_effect_color.getBlue());
1320 writeU8(os, param_type);
1321 writeU8(os, param_type_2);
1322 writeU8(os, is_ground_content);
1323 writeU8(os, light_propagates);
1324 writeU8(os, sunlight_propagates);
1325 writeU8(os, walkable);
1326 writeU8(os, pointable);
1327 writeU8(os, diggable);
1328 writeU8(os, climbable);
1329 writeU8(os, buildable_to);
1330 os<<serializeString(""); // legacy: used to be metadata_name
1331 writeU8(os, liquid_type);
1332 os<<serializeString(liquid_alternative_flowing);
1333 os<<serializeString(liquid_alternative_source);
1334 writeU8(os, liquid_viscosity);
1335 writeU8(os, light_source);
1336 writeU32(os, damage_per_second);
1337 node_box.serialize(os, protocol_version);
1338 selection_box.serialize(os, protocol_version);
1339 writeU8(os, legacy_facedir_simple);
1340 writeU8(os, legacy_wallmounted);
1341 serializeSimpleSoundSpec(sound_footstep, os);
1342 serializeSimpleSoundSpec(sound_dig, os);
1343 serializeSimpleSoundSpec(sound_dug, os);
1345 else if (protocol_version > 13 && protocol_version < 24) {
1346 writeU8(os, 6); // version
1347 os<<serializeString(name);
1348 writeU16(os, groups.size());
1349 for (ItemGroupList::const_iterator
1350 i = groups.begin(); i != groups.end(); ++i) {
1351 os<<serializeString(i->first);
1352 writeS16(os, i->second);
1354 writeU8(os, drawtype);
1355 writeF1000(os, visual_scale);
1357 for (u32 i = 0; i < 6; i++)
1358 tiledef[i].serialize(os, protocol_version);
1359 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1361 for (u32 i = 0; i < 2; i++)
1362 tiledef_special[i].serialize(os, protocol_version);
1364 writeU8(os, post_effect_color.getAlpha());
1365 writeU8(os, post_effect_color.getRed());
1366 writeU8(os, post_effect_color.getGreen());
1367 writeU8(os, post_effect_color.getBlue());
1368 writeU8(os, param_type);
1369 writeU8(os, param_type_2);
1370 writeU8(os, is_ground_content);
1371 writeU8(os, light_propagates);
1372 writeU8(os, sunlight_propagates);
1373 writeU8(os, walkable);
1374 writeU8(os, pointable);
1375 writeU8(os, diggable);
1376 writeU8(os, climbable);
1377 writeU8(os, buildable_to);
1378 os<<serializeString(""); // legacy: used to be metadata_name
1379 writeU8(os, liquid_type);
1380 os<<serializeString(liquid_alternative_flowing);
1381 os<<serializeString(liquid_alternative_source);
1382 writeU8(os, liquid_viscosity);
1383 writeU8(os, liquid_renewable);
1384 writeU8(os, light_source);
1385 writeU32(os, damage_per_second);
1386 node_box.serialize(os, protocol_version);
1387 selection_box.serialize(os, protocol_version);
1388 writeU8(os, legacy_facedir_simple);
1389 writeU8(os, legacy_wallmounted);
1390 serializeSimpleSoundSpec(sound_footstep, os);
1391 serializeSimpleSoundSpec(sound_dig, os);
1392 serializeSimpleSoundSpec(sound_dug, os);
1393 writeU8(os, rightclickable);
1394 writeU8(os, drowning);
1395 writeU8(os, leveled);
1396 writeU8(os, liquid_range);
1398 throw SerializationError("ContentFeatures::serialize(): "
1399 "Unsupported version requested");
1402 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1404 if (version == 5) // In PROTOCOL_VERSION 13
1406 name = deSerializeString(is);
1408 u32 groups_size = readU16(is);
1409 for(u32 i=0; i<groups_size; i++){
1410 std::string name = deSerializeString(is);
1411 int value = readS16(is);
1412 groups[name] = value;
1414 drawtype = (enum NodeDrawType)readU8(is);
1416 visual_scale = readF1000(is);
1417 if (readU8(is) != 6)
1418 throw SerializationError("unsupported tile count");
1419 for (u32 i = 0; i < 6; i++)
1420 tiledef[i].deSerialize(is, version, drawtype);
1421 if (readU8(is) != CF_SPECIAL_COUNT)
1422 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1423 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1424 tiledef_special[i].deSerialize(is, version, drawtype);
1426 post_effect_color.setAlpha(readU8(is));
1427 post_effect_color.setRed(readU8(is));
1428 post_effect_color.setGreen(readU8(is));
1429 post_effect_color.setBlue(readU8(is));
1430 param_type = (enum ContentParamType)readU8(is);
1431 param_type_2 = (enum ContentParamType2)readU8(is);
1432 is_ground_content = readU8(is);
1433 light_propagates = readU8(is);
1434 sunlight_propagates = readU8(is);
1435 walkable = readU8(is);
1436 pointable = readU8(is);
1437 diggable = readU8(is);
1438 climbable = readU8(is);
1439 buildable_to = readU8(is);
1440 deSerializeString(is); // legacy: used to be metadata_name
1441 liquid_type = (enum LiquidType)readU8(is);
1442 liquid_alternative_flowing = deSerializeString(is);
1443 liquid_alternative_source = deSerializeString(is);
1444 liquid_viscosity = readU8(is);
1445 light_source = readU8(is);
1446 light_source = MYMIN(light_source, LIGHT_MAX);
1447 damage_per_second = readU32(is);
1448 node_box.deSerialize(is);
1449 selection_box.deSerialize(is);
1450 legacy_facedir_simple = readU8(is);
1451 legacy_wallmounted = readU8(is);
1452 deSerializeSimpleSoundSpec(sound_footstep, is);
1453 deSerializeSimpleSoundSpec(sound_dig, is);
1454 deSerializeSimpleSoundSpec(sound_dug, is);
1455 } else if (version == 6) {
1456 name = deSerializeString(is);
1458 u32 groups_size = readU16(is);
1459 for (u32 i = 0; i < groups_size; i++) {
1460 std::string name = deSerializeString(is);
1461 int value = readS16(is);
1462 groups[name] = value;
1464 drawtype = (enum NodeDrawType)readU8(is);
1465 visual_scale = readF1000(is);
1466 if (readU8(is) != 6)
1467 throw SerializationError("unsupported tile count");
1468 for (u32 i = 0; i < 6; i++)
1469 tiledef[i].deSerialize(is, version, drawtype);
1470 // CF_SPECIAL_COUNT in version 6 = 2
1471 if (readU8(is) != 2)
1472 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1473 for (u32 i = 0; i < 2; i++)
1474 tiledef_special[i].deSerialize(is, version, drawtype);
1476 post_effect_color.setAlpha(readU8(is));
1477 post_effect_color.setRed(readU8(is));
1478 post_effect_color.setGreen(readU8(is));
1479 post_effect_color.setBlue(readU8(is));
1480 param_type = (enum ContentParamType)readU8(is);
1481 param_type_2 = (enum ContentParamType2)readU8(is);
1482 is_ground_content = readU8(is);
1483 light_propagates = readU8(is);
1484 sunlight_propagates = readU8(is);
1485 walkable = readU8(is);
1486 pointable = readU8(is);
1487 diggable = readU8(is);
1488 climbable = readU8(is);
1489 buildable_to = readU8(is);
1490 deSerializeString(is); // legacy: used to be metadata_name
1491 liquid_type = (enum LiquidType)readU8(is);
1492 liquid_alternative_flowing = deSerializeString(is);
1493 liquid_alternative_source = deSerializeString(is);
1494 liquid_viscosity = readU8(is);
1495 liquid_renewable = readU8(is);
1496 light_source = readU8(is);
1497 damage_per_second = readU32(is);
1498 node_box.deSerialize(is);
1499 selection_box.deSerialize(is);
1500 legacy_facedir_simple = readU8(is);
1501 legacy_wallmounted = readU8(is);
1502 deSerializeSimpleSoundSpec(sound_footstep, is);
1503 deSerializeSimpleSoundSpec(sound_dig, is);
1504 deSerializeSimpleSoundSpec(sound_dug, is);
1505 rightclickable = readU8(is);
1506 drowning = readU8(is);
1507 leveled = readU8(is);
1508 liquid_range = readU8(is);
1510 throw SerializationError("unsupported ContentFeatures version");
1515 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1517 return m_node_registration_complete;
1521 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1523 m_node_registration_complete = completed;
1527 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1530 if (m_node_registration_complete)
1531 nr->nodeResolveInternal();
1533 m_pending_resolve_callbacks.push_back(nr);
1537 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1539 size_t len = m_pending_resolve_callbacks.size();
1540 for (size_t i = 0; i != len; i++) {
1541 if (nr != m_pending_resolve_callbacks[i])
1545 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1546 m_pending_resolve_callbacks.resize(len);
1554 void CNodeDefManager::runNodeResolveCallbacks()
1556 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1557 NodeResolver *nr = m_pending_resolve_callbacks[i];
1558 nr->nodeResolveInternal();
1561 m_pending_resolve_callbacks.clear();
1565 void CNodeDefManager::resetNodeResolveState()
1567 m_node_registration_complete = false;
1568 m_pending_resolve_callbacks.clear();
1571 void CNodeDefManager::mapNodeboxConnections()
1573 for (u32 i = 0; i < m_content_features.size(); i++) {
1574 ContentFeatures *f = &m_content_features[i];
1575 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1577 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1578 it != f->connects_to.end(); ++it) {
1579 getIds(*it, f->connects_to_ids);
1584 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1586 const ContentFeatures &f1 = get(from);
1588 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1591 // lookup target in connected set
1592 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1595 const ContentFeatures &f2 = get(to);
1597 if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1598 // ignores actually looking if back connection exists
1599 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1601 // does to node declare usable faces?
1602 if (f2.connect_sides > 0) {
1603 if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
1604 static const u8 rot[33 * 4] = {
1605 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1606 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
1607 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
1608 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1609 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
1610 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1612 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1613 32, 16, 8, 4 // 32 - left
1615 return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
1617 return (f2.connect_sides & connect_face);
1619 // the target is just a regular node, so connect no matter back connection
1627 NodeResolver::NodeResolver()
1630 m_nodenames_idx = 0;
1631 m_nnlistsizes_idx = 0;
1632 m_resolve_done = false;
1634 m_nodenames.reserve(16);
1635 m_nnlistsizes.reserve(4);
1639 NodeResolver::~NodeResolver()
1641 if (!m_resolve_done && m_ndef)
1642 m_ndef->cancelNodeResolveCallback(this);
1646 void NodeResolver::nodeResolveInternal()
1648 m_nodenames_idx = 0;
1649 m_nnlistsizes_idx = 0;
1652 m_resolve_done = true;
1654 m_nodenames.clear();
1655 m_nnlistsizes.clear();
1659 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1660 const std::string &node_alt, content_t c_fallback)
1662 if (m_nodenames_idx == m_nodenames.size()) {
1663 *result_out = c_fallback;
1664 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1669 std::string name = m_nodenames[m_nodenames_idx++];
1671 bool success = m_ndef->getId(name, c);
1672 if (!success && node_alt != "") {
1674 success = m_ndef->getId(name, c);
1678 errorstream << "NodeResolver: failed to resolve node name '" << name
1679 << "'." << std::endl;
1688 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1689 bool all_required, content_t c_fallback)
1691 bool success = true;
1693 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1694 errorstream << "NodeResolver: no more node lists" << std::endl;
1698 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1701 if (m_nodenames_idx == m_nodenames.size()) {
1702 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1707 std::string &name = m_nodenames[m_nodenames_idx++];
1709 if (name.substr(0,6) != "group:") {
1710 if (m_ndef->getId(name, c)) {
1711 result_out->push_back(c);
1712 } else if (all_required) {
1713 errorstream << "NodeResolver: failed to resolve node name '"
1714 << name << "'." << std::endl;
1715 result_out->push_back(c_fallback);
1719 std::set<content_t> cids;
1720 std::set<content_t>::iterator it;
1721 m_ndef->getIds(name, cids);
1722 for (it = cids.begin(); it != cids.end(); ++it)
1723 result_out->push_back(*it);