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);
254 ContentFeatures::ContentFeatures()
259 ContentFeatures::~ContentFeatures()
263 void ContentFeatures::reset()
270 visual_solidness = 0;
271 backface_culling = true;
274 has_on_construct = false;
275 has_on_destruct = false;
276 has_after_destruct = false;
280 NOTE: Most of this is always overridden by the default values given
285 // Unknown nodes can be dug
286 groups["dig_immediate"] = 2;
287 drawtype = NDT_NORMAL;
290 for(u32 i = 0; i < 24; i++)
292 minimap_color = video::SColor(0, 0, 0, 0);
295 for(u32 i = 0; i < 6; i++)
296 tiledef[i] = TileDef();
297 for(u16 j = 0; j < CF_SPECIAL_COUNT; j++)
298 tiledef_special[j] = TileDef();
300 post_effect_color = video::SColor(0, 0, 0, 0);
301 param_type = CPT_NONE;
302 param_type_2 = CPT2_NONE;
303 is_ground_content = false;
304 light_propagates = false;
305 sunlight_propagates = false;
310 buildable_to = false;
312 rightclickable = true;
314 liquid_type = LIQUID_NONE;
315 liquid_alternative_flowing = "";
316 liquid_alternative_source = "";
317 liquid_viscosity = 0;
318 liquid_renewable = true;
319 liquid_range = LIQUID_LEVEL_MAX+1;
322 damage_per_second = 0;
323 node_box = NodeBox();
324 selection_box = NodeBox();
325 collision_box = NodeBox();
327 legacy_facedir_simple = false;
328 legacy_wallmounted = false;
329 sound_footstep = SimpleSoundSpec();
330 sound_dig = SimpleSoundSpec("__group");
331 sound_dug = SimpleSoundSpec();
333 connects_to_ids.clear();
337 void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
339 if(protocol_version < 24){
340 serializeOld(os, protocol_version);
344 writeU8(os, protocol_version < 27 ? 7 : 8);
346 os<<serializeString(name);
347 writeU16(os, groups.size());
348 for(ItemGroupList::const_iterator
349 i = groups.begin(); i != groups.end(); ++i){
350 os<<serializeString(i->first);
351 writeS16(os, i->second);
353 writeU8(os, drawtype);
354 writeF1000(os, visual_scale);
356 for(u32 i = 0; i < 6; i++)
357 tiledef[i].serialize(os, protocol_version);
358 writeU8(os, CF_SPECIAL_COUNT);
359 for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
360 tiledef_special[i].serialize(os, protocol_version);
363 writeU8(os, post_effect_color.getAlpha());
364 writeU8(os, post_effect_color.getRed());
365 writeU8(os, post_effect_color.getGreen());
366 writeU8(os, post_effect_color.getBlue());
367 writeU8(os, param_type);
368 writeU8(os, param_type_2);
369 writeU8(os, is_ground_content);
370 writeU8(os, light_propagates);
371 writeU8(os, sunlight_propagates);
372 writeU8(os, walkable);
373 writeU8(os, pointable);
374 writeU8(os, diggable);
375 writeU8(os, climbable);
376 writeU8(os, buildable_to);
377 os<<serializeString(""); // legacy: used to be metadata_name
378 writeU8(os, liquid_type);
379 os<<serializeString(liquid_alternative_flowing);
380 os<<serializeString(liquid_alternative_source);
381 writeU8(os, liquid_viscosity);
382 writeU8(os, liquid_renewable);
383 writeU8(os, light_source);
384 writeU32(os, damage_per_second);
385 node_box.serialize(os, protocol_version);
386 selection_box.serialize(os, protocol_version);
387 writeU8(os, legacy_facedir_simple);
388 writeU8(os, legacy_wallmounted);
389 serializeSimpleSoundSpec(sound_footstep, os);
390 serializeSimpleSoundSpec(sound_dig, os);
391 serializeSimpleSoundSpec(sound_dug, os);
392 writeU8(os, rightclickable);
393 writeU8(os, drowning);
394 writeU8(os, leveled);
395 writeU8(os, liquid_range);
397 // Stuff below should be moved to correct place in a version that otherwise changes
398 // the protocol version
399 os<<serializeString(mesh);
400 collision_box.serialize(os, protocol_version);
401 writeU8(os, floodable);
402 writeU16(os, connects_to_ids.size());
403 for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
404 i != connects_to_ids.end(); ++i)
406 writeU8(os, connect_sides);
409 void ContentFeatures::deSerialize(std::istream &is)
411 int version = readU8(is);
413 deSerializeOld(is, version);
415 } else if (version > 8) {
416 throw SerializationError("unsupported ContentFeatures version");
419 name = deSerializeString(is);
421 u32 groups_size = readU16(is);
422 for(u32 i = 0; i < groups_size; i++){
423 std::string name = deSerializeString(is);
424 int value = readS16(is);
425 groups[name] = value;
427 drawtype = (enum NodeDrawType)readU8(is);
429 visual_scale = readF1000(is);
431 throw SerializationError("unsupported tile count");
432 for(u32 i = 0; i < 6; i++)
433 tiledef[i].deSerialize(is, version, drawtype);
434 if(readU8(is) != CF_SPECIAL_COUNT)
435 throw SerializationError("unsupported CF_SPECIAL_COUNT");
436 for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
437 tiledef_special[i].deSerialize(is, version, drawtype);
439 post_effect_color.setAlpha(readU8(is));
440 post_effect_color.setRed(readU8(is));
441 post_effect_color.setGreen(readU8(is));
442 post_effect_color.setBlue(readU8(is));
443 param_type = (enum ContentParamType)readU8(is);
444 param_type_2 = (enum ContentParamType2)readU8(is);
445 is_ground_content = readU8(is);
446 light_propagates = readU8(is);
447 sunlight_propagates = readU8(is);
448 walkable = readU8(is);
449 pointable = readU8(is);
450 diggable = readU8(is);
451 climbable = readU8(is);
452 buildable_to = readU8(is);
453 deSerializeString(is); // legacy: used to be metadata_name
454 liquid_type = (enum LiquidType)readU8(is);
455 liquid_alternative_flowing = deSerializeString(is);
456 liquid_alternative_source = deSerializeString(is);
457 liquid_viscosity = readU8(is);
458 liquid_renewable = readU8(is);
459 light_source = readU8(is);
460 damage_per_second = readU32(is);
461 node_box.deSerialize(is);
462 selection_box.deSerialize(is);
463 legacy_facedir_simple = readU8(is);
464 legacy_wallmounted = readU8(is);
465 deSerializeSimpleSoundSpec(sound_footstep, is);
466 deSerializeSimpleSoundSpec(sound_dig, is);
467 deSerializeSimpleSoundSpec(sound_dug, is);
468 rightclickable = readU8(is);
469 drowning = readU8(is);
470 leveled = readU8(is);
471 liquid_range = readU8(is);
473 // If you add anything here, insert it primarily inside the try-catch
474 // block to not need to increase the version.
476 // Stuff below should be moved to correct place in a version that
477 // otherwise changes the protocol version
478 mesh = deSerializeString(is);
479 collision_box.deSerialize(is);
480 floodable = readU8(is);
481 u16 connects_to_size = readU16(is);
482 for (u16 i = 0; i < connects_to_size; i++)
483 connects_to_ids.insert(readU16(is));
484 connect_sides = readU8(is);
485 }catch(SerializationError &e) {};
492 class CNodeDefManager: public IWritableNodeDefManager {
495 virtual ~CNodeDefManager();
497 virtual IWritableNodeDefManager *clone();
498 inline virtual const ContentFeatures& get(content_t c) const;
499 inline virtual const ContentFeatures& get(const MapNode &n) const;
500 virtual bool getId(const std::string &name, content_t &result) const;
501 virtual content_t getId(const std::string &name) const;
502 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
503 virtual const ContentFeatures& get(const std::string &name) const;
504 content_t allocateId();
505 virtual content_t set(const std::string &name, const ContentFeatures &def);
506 virtual content_t allocateDummy(const std::string &name);
507 virtual void updateAliases(IItemDefManager *idef);
508 virtual void applyTextureOverrides(const std::string &override_filepath);
509 virtual void updateTextures(IGameDef *gamedef,
510 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
511 void *progress_cbk_args);
512 void serialize(std::ostream &os, u16 protocol_version) const;
513 void deSerialize(std::istream &is);
515 inline virtual bool getNodeRegistrationStatus() const;
516 inline virtual void setNodeRegistrationStatus(bool completed);
518 virtual void pendNodeResolve(NodeResolver *nr);
519 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
520 virtual void runNodeResolveCallbacks();
521 virtual void resetNodeResolveState();
522 virtual void mapNodeboxConnections();
523 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
526 void addNameIdMapping(content_t i, std::string name);
528 void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
529 u32 shader_id, bool use_normal_texture, bool backface_culling,
530 u8 alpha, u8 material_type);
533 // Features indexed by id
534 std::vector<ContentFeatures> m_content_features;
536 // A mapping for fast converting back and forth between names and ids
537 NameIdMapping m_name_id_mapping;
539 // Like m_name_id_mapping, but only from names to ids, and includes
540 // item aliases too. Updated by updateAliases()
541 // Note: Not serialized.
543 std::map<std::string, content_t> m_name_id_mapping_with_aliases;
545 // A mapping from groups to a list of content_ts (and their levels)
546 // that belong to it. Necessary for a direct lookup in getIds().
547 // Note: Not serialized.
548 std::map<std::string, GroupItems> m_group_to_items;
550 // Next possibly free id
553 // NodeResolvers to callback once node registration has ended
554 std::vector<NodeResolver *> m_pending_resolve_callbacks;
556 // True when all nodes have been registered
557 bool m_node_registration_complete;
561 CNodeDefManager::CNodeDefManager()
567 CNodeDefManager::~CNodeDefManager()
570 for (u32 i = 0; i < m_content_features.size(); i++) {
571 ContentFeatures *f = &m_content_features[i];
572 for (u32 j = 0; j < 24; j++) {
574 f->mesh_ptr[j]->drop();
581 void CNodeDefManager::clear()
583 m_content_features.clear();
584 m_name_id_mapping.clear();
585 m_name_id_mapping_with_aliases.clear();
586 m_group_to_items.clear();
589 resetNodeResolveState();
591 u32 initial_length = 0;
592 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
593 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
594 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
595 m_content_features.resize(initial_length);
597 // Set CONTENT_UNKNOWN
601 // Insert directly into containers
602 content_t c = CONTENT_UNKNOWN;
603 m_content_features[c] = f;
604 addNameIdMapping(c, f.name);
611 f.drawtype = NDT_AIRLIKE;
612 f.param_type = CPT_LIGHT;
613 f.light_propagates = true;
614 f.sunlight_propagates = true;
618 f.buildable_to = true;
620 f.is_ground_content = true;
621 // Insert directly into containers
622 content_t c = CONTENT_AIR;
623 m_content_features[c] = f;
624 addNameIdMapping(c, f.name);
627 // Set CONTENT_IGNORE
631 f.drawtype = NDT_AIRLIKE;
632 f.param_type = CPT_NONE;
633 f.light_propagates = false;
634 f.sunlight_propagates = false;
638 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
639 f.is_ground_content = true;
640 // Insert directly into containers
641 content_t c = CONTENT_IGNORE;
642 m_content_features[c] = f;
643 addNameIdMapping(c, f.name);
648 IWritableNodeDefManager *CNodeDefManager::clone()
650 CNodeDefManager *mgr = new CNodeDefManager();
656 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
658 return c < m_content_features.size()
659 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
663 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
665 return get(n.getContent());
669 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
671 std::map<std::string, content_t>::const_iterator
672 i = m_name_id_mapping_with_aliases.find(name);
673 if(i == m_name_id_mapping_with_aliases.end())
680 content_t CNodeDefManager::getId(const std::string &name) const
682 content_t id = CONTENT_IGNORE;
688 bool CNodeDefManager::getIds(const std::string &name,
689 std::set<content_t> &result) const
691 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
692 if (name.substr(0,6) != "group:") {
693 content_t id = CONTENT_IGNORE;
694 bool exists = getId(name, id);
699 std::string group = name.substr(6);
701 std::map<std::string, GroupItems>::const_iterator
702 i = m_group_to_items.find(group);
703 if (i == m_group_to_items.end())
706 const GroupItems &items = i->second;
707 for (GroupItems::const_iterator j = items.begin();
708 j != items.end(); ++j) {
709 if ((*j).second != 0)
710 result.insert((*j).first);
712 //printf("getIds: %dus\n", t.stop());
717 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
719 content_t id = CONTENT_UNKNOWN;
725 // returns CONTENT_IGNORE if no free ID found
726 content_t CNodeDefManager::allocateId()
728 for (content_t id = m_next_id;
729 id >= m_next_id; // overflow?
731 while (id >= m_content_features.size()) {
732 m_content_features.push_back(ContentFeatures());
734 const ContentFeatures &f = m_content_features[id];
740 // If we arrive here, an overflow occurred in id.
741 // That means no ID was found
742 return CONTENT_IGNORE;
746 // IWritableNodeDefManager
747 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
751 assert(name == def.name);
753 // Don't allow redefining ignore (but allow air and unknown)
754 if (name == "ignore") {
755 warningstream << "NodeDefManager: Ignoring "
756 "CONTENT_IGNORE redefinition"<<std::endl;
757 return CONTENT_IGNORE;
760 content_t id = CONTENT_IGNORE;
761 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
764 if (id == CONTENT_IGNORE) {
765 warningstream << "NodeDefManager: Absolute "
766 "limit reached" << std::endl;
767 return CONTENT_IGNORE;
769 assert(id != CONTENT_IGNORE);
770 addNameIdMapping(id, name);
772 m_content_features[id] = def;
773 verbosestream << "NodeDefManager: registering content id \"" << id
774 << "\": name=\"" << def.name << "\""<<std::endl;
776 // Add this content to the list of all groups it belongs to
777 // FIXME: This should remove a node from groups it no longer
778 // belongs to when a node is re-registered
779 for (ItemGroupList::const_iterator i = def.groups.begin();
780 i != def.groups.end(); ++i) {
781 std::string group_name = i->first;
783 std::map<std::string, GroupItems>::iterator
784 j = m_group_to_items.find(group_name);
785 if (j == m_group_to_items.end()) {
786 m_group_to_items[group_name].push_back(
787 std::make_pair(id, i->second));
789 GroupItems &items = j->second;
790 items.push_back(std::make_pair(id, i->second));
797 content_t CNodeDefManager::allocateDummy(const std::string &name)
799 assert(name != ""); // Pre-condition
806 void CNodeDefManager::updateAliases(IItemDefManager *idef)
808 std::set<std::string> all = idef->getAll();
809 m_name_id_mapping_with_aliases.clear();
810 for (std::set<std::string>::iterator
811 i = all.begin(); i != all.end(); ++i) {
812 std::string name = *i;
813 std::string convert_to = idef->getAlias(name);
815 if (m_name_id_mapping.getId(convert_to, id)) {
816 m_name_id_mapping_with_aliases.insert(
817 std::make_pair(name, id));
822 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
824 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
825 "overrides to textures from " << override_filepath << std::endl;
827 std::ifstream infile(override_filepath.c_str());
830 while (std::getline(infile, line)) {
832 if (trim(line) == "")
834 std::vector<std::string> splitted = str_split(line, ' ');
835 if (splitted.size() != 3) {
836 errorstream << override_filepath
837 << ":" << line_c << " Could not apply texture override \""
838 << line << "\": Syntax error" << std::endl;
843 if (!getId(splitted[0], id)) {
844 errorstream << override_filepath
845 << ":" << line_c << " Could not apply texture override \""
846 << line << "\": Unknown node \""
847 << splitted[0] << "\"" << std::endl;
851 ContentFeatures &nodedef = m_content_features[id];
853 if (splitted[1] == "top")
854 nodedef.tiledef[0].name = splitted[2];
855 else if (splitted[1] == "bottom")
856 nodedef.tiledef[1].name = splitted[2];
857 else if (splitted[1] == "right")
858 nodedef.tiledef[2].name = splitted[2];
859 else if (splitted[1] == "left")
860 nodedef.tiledef[3].name = splitted[2];
861 else if (splitted[1] == "back")
862 nodedef.tiledef[4].name = splitted[2];
863 else if (splitted[1] == "front")
864 nodedef.tiledef[5].name = splitted[2];
865 else if (splitted[1] == "all" || splitted[1] == "*")
866 for (int i = 0; i < 6; i++)
867 nodedef.tiledef[i].name = splitted[2];
868 else if (splitted[1] == "sides")
869 for (int i = 2; i < 6; i++)
870 nodedef.tiledef[i].name = splitted[2];
872 errorstream << override_filepath
873 << ":" << line_c << " Could not apply texture override \""
874 << line << "\": Unknown node side \""
875 << splitted[1] << "\"" << std::endl;
881 void CNodeDefManager::updateTextures(IGameDef *gamedef,
882 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
883 void *progress_callback_args)
886 infostream << "CNodeDefManager::updateTextures(): Updating "
887 "textures in node definitions" << std::endl;
888 ITextureSource *tsrc = gamedef->tsrc();
889 IShaderSource *shdsrc = gamedef->getShaderSource();
890 scene::ISceneManager* smgr = gamedef->getSceneManager();
891 scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
893 bool connected_glass = g_settings->getBool("connected_glass");
894 bool opaque_water = g_settings->getBool("opaque_water");
895 bool enable_shaders = g_settings->getBool("enable_shaders");
896 bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
897 bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
898 bool enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
899 bool enable_minimap = g_settings->getBool("enable_minimap");
900 std::string leaves_style = g_settings->get("leaves_style");
902 bool use_normal_texture = enable_shaders &&
903 (enable_bumpmapping || enable_parallax_occlusion);
905 u32 size = m_content_features.size();
907 for (u32 i = 0; i < size; i++) {
908 ContentFeatures *f = &m_content_features[i];
910 // minimap pixel color - the average color of a texture
911 if (enable_minimap && f->tiledef[0].name != "")
912 f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
914 // Figure out the actual tiles to use
916 for (u32 j = 0; j < 6; j++) {
917 tiledef[j] = f->tiledef[j];
918 if (tiledef[j].name == "")
919 tiledef[j].name = "unknown_node.png";
922 bool is_liquid = false;
923 bool is_water_surface = false;
925 u8 material_type = (f->alpha == 255) ?
926 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
928 switch (f->drawtype) {
937 assert(f->liquid_type == LIQUID_SOURCE);
943 case NDT_FLOWINGLIQUID:
944 assert(f->liquid_type == LIQUID_FLOWING);
952 f->visual_solidness = 1;
954 case NDT_GLASSLIKE_FRAMED:
956 f->visual_solidness = 1;
958 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
960 f->visual_solidness = 1;
961 f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
965 f->visual_solidness = 1;
967 case NDT_ALLFACES_OPTIONAL:
968 if (leaves_style == "fancy") {
969 f->drawtype = NDT_ALLFACES;
971 f->visual_solidness = 1;
972 } else if (leaves_style == "simple") {
973 for (u32 j = 0; j < 6; j++) {
974 if (f->tiledef_special[j].name != "")
975 tiledef[j].name = f->tiledef_special[j].name;
977 f->drawtype = NDT_GLASSLIKE;
979 f->visual_solidness = 1;
981 f->drawtype = NDT_NORMAL;
983 for (u32 i = 0; i < 6; i++)
984 tiledef[i].name += std::string("^[noalpha");
987 material_type = TILE_MATERIAL_WAVING_LEAVES;
992 material_type = TILE_MATERIAL_WAVING_PLANTS;
1010 material_type = (f->alpha == 255) ?
1011 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
1012 if (f->name == "default:water_source")
1013 is_water_surface = true;
1017 for (u16 j = 0; j < 6; j++) {
1018 tile_shader[j] = shdsrc->getShader("nodes_shader",
1019 material_type, f->drawtype);
1022 if (is_water_surface) {
1023 tile_shader[0] = shdsrc->getShader("water_surface_shader",
1024 material_type, f->drawtype);
1027 // Tiles (fill in f->tiles[])
1028 for (u16 j = 0; j < 6; j++) {
1029 fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
1030 use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type);
1033 // Special tiles (fill in f->special_tiles[])
1034 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
1035 fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
1036 tile_shader[j], use_normal_texture,
1037 f->tiledef_special[j].backface_culling, f->alpha, material_type);
1040 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
1041 // Meshnode drawtype
1042 // Read the mesh and apply scale
1043 f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
1044 if (f->mesh_ptr[0]){
1045 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
1046 scaleMesh(f->mesh_ptr[0], scale);
1047 recalculateBoundingBox(f->mesh_ptr[0]);
1048 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1050 } else if ((f->drawtype == NDT_NODEBOX) &&
1051 ((f->node_box.type == NODEBOX_REGULAR) ||
1052 (f->node_box.type == NODEBOX_FIXED)) &&
1053 (!f->node_box.fixed.empty())) {
1054 //Convert regular nodebox nodes to meshnodes
1055 //Change the drawtype and apply scale
1056 f->drawtype = NDT_MESH;
1057 f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed);
1058 v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
1059 scaleMesh(f->mesh_ptr[0], scale);
1060 recalculateBoundingBox(f->mesh_ptr[0]);
1061 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1064 //Cache 6dfacedir and wallmounted rotated clones of meshes
1065 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
1066 for (u16 j = 1; j < 24; j++) {
1067 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1068 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
1069 recalculateBoundingBox(f->mesh_ptr[j]);
1070 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1072 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
1073 static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
1074 for (u16 j = 1; j < 6; j++) {
1075 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1076 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
1077 recalculateBoundingBox(f->mesh_ptr[j]);
1078 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1080 rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
1081 recalculateBoundingBox(f->mesh_ptr[0]);
1082 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1085 progress_callback(progress_callback_args, i, size);
1092 void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
1093 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
1094 bool backface_culling, u8 alpha, u8 material_type)
1096 tile->shader_id = shader_id;
1097 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
1098 tile->alpha = alpha;
1099 tile->material_type = material_type;
1101 // Normal texture and shader flags texture
1102 if (use_normal_texture) {
1103 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
1105 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
1108 tile->material_flags = 0;
1109 if (backface_culling)
1110 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
1111 if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
1112 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1113 if (tiledef->tileable_horizontal)
1114 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
1115 if (tiledef->tileable_vertical)
1116 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
1118 // Animation parameters
1119 int frame_count = 1;
1120 if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
1121 // Get texture size to determine frame count by aspect ratio
1122 v2u32 size = tile->texture->getOriginalSize();
1123 int frame_height = (float)size.X /
1124 (float)tiledef->animation.aspect_w *
1125 (float)tiledef->animation.aspect_h;
1126 frame_count = size.Y / frame_height;
1127 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
1128 tile->animation_frame_count = frame_count;
1129 tile->animation_frame_length_ms = frame_length_ms;
1132 if (frame_count == 1) {
1133 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1135 std::ostringstream os(std::ios::binary);
1136 tile->frames.resize(frame_count);
1138 for (int i = 0; i < frame_count; i++) {
1143 os << tiledef->name << "^[verticalframe:"
1144 << frame_count << ":" << i;
1146 frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
1147 if (tile->normal_texture)
1148 frame.normal_texture = tsrc->getNormalTexture(os.str());
1149 frame.flags_texture = tile->flags_texture;
1150 tile->frames[i] = frame;
1157 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1159 writeU8(os, 1); // version
1161 std::ostringstream os2(std::ios::binary);
1162 for (u32 i = 0; i < m_content_features.size(); i++) {
1163 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1164 || i == CONTENT_UNKNOWN)
1166 const ContentFeatures *f = &m_content_features[i];
1170 // Wrap it in a string to allow different lengths without
1171 // strict version incompatibilities
1172 std::ostringstream wrapper_os(std::ios::binary);
1173 f->serialize(wrapper_os, protocol_version);
1174 os2<<serializeString(wrapper_os.str());
1176 // must not overflow
1177 u16 next = count + 1;
1178 FATAL_ERROR_IF(next < count, "Overflow");
1181 writeU16(os, count);
1182 os << serializeLongString(os2.str());
1186 void CNodeDefManager::deSerialize(std::istream &is)
1189 int version = readU8(is);
1191 throw SerializationError("unsupported NodeDefinitionManager version");
1192 u16 count = readU16(is);
1193 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1195 for (u16 n = 0; n < count; n++) {
1196 u16 i = readU16(is2);
1198 // Read it from the string wrapper
1199 std::string wrapper = deSerializeString(is2);
1200 std::istringstream wrapper_is(wrapper, std::ios::binary);
1201 f.deSerialize(wrapper_is);
1203 // Check error conditions
1204 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1205 warningstream << "NodeDefManager::deSerialize(): "
1206 "not changing builtin node " << i << std::endl;
1210 warningstream << "NodeDefManager::deSerialize(): "
1211 "received empty name" << std::endl;
1217 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1218 warningstream << "NodeDefManager::deSerialize(): "
1219 "already defined with different ID: " << f.name << std::endl;
1223 // All is ok, add node definition with the requested ID
1224 if (i >= m_content_features.size())
1225 m_content_features.resize((u32)(i) + 1);
1226 m_content_features[i] = f;
1227 addNameIdMapping(i, f.name);
1228 verbosestream << "deserialized " << f.name << std::endl;
1233 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1235 m_name_id_mapping.set(i, name);
1236 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1240 IWritableNodeDefManager *createNodeDefManager()
1242 return new CNodeDefManager();
1246 //// Serialization of old ContentFeatures formats
1247 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1249 if (protocol_version == 13)
1251 writeU8(os, 5); // version
1252 os<<serializeString(name);
1253 writeU16(os, groups.size());
1254 for (ItemGroupList::const_iterator
1255 i = groups.begin(); i != groups.end(); ++i) {
1256 os<<serializeString(i->first);
1257 writeS16(os, i->second);
1259 writeU8(os, drawtype);
1260 writeF1000(os, visual_scale);
1262 for (u32 i = 0; i < 6; i++)
1263 tiledef[i].serialize(os, protocol_version);
1264 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1266 for (u32 i = 0; i < 2; i++)
1267 tiledef_special[i].serialize(os, protocol_version);
1269 writeU8(os, post_effect_color.getAlpha());
1270 writeU8(os, post_effect_color.getRed());
1271 writeU8(os, post_effect_color.getGreen());
1272 writeU8(os, post_effect_color.getBlue());
1273 writeU8(os, param_type);
1274 writeU8(os, param_type_2);
1275 writeU8(os, is_ground_content);
1276 writeU8(os, light_propagates);
1277 writeU8(os, sunlight_propagates);
1278 writeU8(os, walkable);
1279 writeU8(os, pointable);
1280 writeU8(os, diggable);
1281 writeU8(os, climbable);
1282 writeU8(os, buildable_to);
1283 os<<serializeString(""); // legacy: used to be metadata_name
1284 writeU8(os, liquid_type);
1285 os<<serializeString(liquid_alternative_flowing);
1286 os<<serializeString(liquid_alternative_source);
1287 writeU8(os, liquid_viscosity);
1288 writeU8(os, light_source);
1289 writeU32(os, damage_per_second);
1290 node_box.serialize(os, protocol_version);
1291 selection_box.serialize(os, protocol_version);
1292 writeU8(os, legacy_facedir_simple);
1293 writeU8(os, legacy_wallmounted);
1294 serializeSimpleSoundSpec(sound_footstep, os);
1295 serializeSimpleSoundSpec(sound_dig, os);
1296 serializeSimpleSoundSpec(sound_dug, os);
1298 else if (protocol_version > 13 && protocol_version < 24) {
1299 writeU8(os, 6); // version
1300 os<<serializeString(name);
1301 writeU16(os, groups.size());
1302 for (ItemGroupList::const_iterator
1303 i = groups.begin(); i != groups.end(); ++i) {
1304 os<<serializeString(i->first);
1305 writeS16(os, i->second);
1307 writeU8(os, drawtype);
1308 writeF1000(os, visual_scale);
1310 for (u32 i = 0; i < 6; i++)
1311 tiledef[i].serialize(os, protocol_version);
1312 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1314 for (u32 i = 0; i < 2; i++)
1315 tiledef_special[i].serialize(os, protocol_version);
1317 writeU8(os, post_effect_color.getAlpha());
1318 writeU8(os, post_effect_color.getRed());
1319 writeU8(os, post_effect_color.getGreen());
1320 writeU8(os, post_effect_color.getBlue());
1321 writeU8(os, param_type);
1322 writeU8(os, param_type_2);
1323 writeU8(os, is_ground_content);
1324 writeU8(os, light_propagates);
1325 writeU8(os, sunlight_propagates);
1326 writeU8(os, walkable);
1327 writeU8(os, pointable);
1328 writeU8(os, diggable);
1329 writeU8(os, climbable);
1330 writeU8(os, buildable_to);
1331 os<<serializeString(""); // legacy: used to be metadata_name
1332 writeU8(os, liquid_type);
1333 os<<serializeString(liquid_alternative_flowing);
1334 os<<serializeString(liquid_alternative_source);
1335 writeU8(os, liquid_viscosity);
1336 writeU8(os, liquid_renewable);
1337 writeU8(os, light_source);
1338 writeU32(os, damage_per_second);
1339 node_box.serialize(os, protocol_version);
1340 selection_box.serialize(os, protocol_version);
1341 writeU8(os, legacy_facedir_simple);
1342 writeU8(os, legacy_wallmounted);
1343 serializeSimpleSoundSpec(sound_footstep, os);
1344 serializeSimpleSoundSpec(sound_dig, os);
1345 serializeSimpleSoundSpec(sound_dug, os);
1346 writeU8(os, rightclickable);
1347 writeU8(os, drowning);
1348 writeU8(os, leveled);
1349 writeU8(os, liquid_range);
1351 throw SerializationError("ContentFeatures::serialize(): "
1352 "Unsupported version requested");
1355 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1357 if (version == 5) // In PROTOCOL_VERSION 13
1359 name = deSerializeString(is);
1361 u32 groups_size = readU16(is);
1362 for(u32 i=0; i<groups_size; i++){
1363 std::string name = deSerializeString(is);
1364 int value = readS16(is);
1365 groups[name] = value;
1367 drawtype = (enum NodeDrawType)readU8(is);
1369 visual_scale = readF1000(is);
1370 if (readU8(is) != 6)
1371 throw SerializationError("unsupported tile count");
1372 for (u32 i = 0; i < 6; i++)
1373 tiledef[i].deSerialize(is, version, drawtype);
1374 if (readU8(is) != CF_SPECIAL_COUNT)
1375 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1376 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1377 tiledef_special[i].deSerialize(is, version, drawtype);
1379 post_effect_color.setAlpha(readU8(is));
1380 post_effect_color.setRed(readU8(is));
1381 post_effect_color.setGreen(readU8(is));
1382 post_effect_color.setBlue(readU8(is));
1383 param_type = (enum ContentParamType)readU8(is);
1384 param_type_2 = (enum ContentParamType2)readU8(is);
1385 is_ground_content = readU8(is);
1386 light_propagates = readU8(is);
1387 sunlight_propagates = readU8(is);
1388 walkable = readU8(is);
1389 pointable = readU8(is);
1390 diggable = readU8(is);
1391 climbable = readU8(is);
1392 buildable_to = readU8(is);
1393 deSerializeString(is); // legacy: used to be metadata_name
1394 liquid_type = (enum LiquidType)readU8(is);
1395 liquid_alternative_flowing = deSerializeString(is);
1396 liquid_alternative_source = deSerializeString(is);
1397 liquid_viscosity = readU8(is);
1398 light_source = readU8(is);
1399 damage_per_second = readU32(is);
1400 node_box.deSerialize(is);
1401 selection_box.deSerialize(is);
1402 legacy_facedir_simple = readU8(is);
1403 legacy_wallmounted = readU8(is);
1404 deSerializeSimpleSoundSpec(sound_footstep, is);
1405 deSerializeSimpleSoundSpec(sound_dig, is);
1406 deSerializeSimpleSoundSpec(sound_dug, is);
1407 } else if (version == 6) {
1408 name = deSerializeString(is);
1410 u32 groups_size = readU16(is);
1411 for (u32 i = 0; i < groups_size; i++) {
1412 std::string name = deSerializeString(is);
1413 int value = readS16(is);
1414 groups[name] = value;
1416 drawtype = (enum NodeDrawType)readU8(is);
1417 visual_scale = readF1000(is);
1418 if (readU8(is) != 6)
1419 throw SerializationError("unsupported tile count");
1420 for (u32 i = 0; i < 6; i++)
1421 tiledef[i].deSerialize(is, version, drawtype);
1422 // CF_SPECIAL_COUNT in version 6 = 2
1423 if (readU8(is) != 2)
1424 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1425 for (u32 i = 0; i < 2; i++)
1426 tiledef_special[i].deSerialize(is, version, drawtype);
1428 post_effect_color.setAlpha(readU8(is));
1429 post_effect_color.setRed(readU8(is));
1430 post_effect_color.setGreen(readU8(is));
1431 post_effect_color.setBlue(readU8(is));
1432 param_type = (enum ContentParamType)readU8(is);
1433 param_type_2 = (enum ContentParamType2)readU8(is);
1434 is_ground_content = readU8(is);
1435 light_propagates = readU8(is);
1436 sunlight_propagates = readU8(is);
1437 walkable = readU8(is);
1438 pointable = readU8(is);
1439 diggable = readU8(is);
1440 climbable = readU8(is);
1441 buildable_to = readU8(is);
1442 deSerializeString(is); // legacy: used to be metadata_name
1443 liquid_type = (enum LiquidType)readU8(is);
1444 liquid_alternative_flowing = deSerializeString(is);
1445 liquid_alternative_source = deSerializeString(is);
1446 liquid_viscosity = readU8(is);
1447 liquid_renewable = readU8(is);
1448 light_source = readU8(is);
1449 damage_per_second = readU32(is);
1450 node_box.deSerialize(is);
1451 selection_box.deSerialize(is);
1452 legacy_facedir_simple = readU8(is);
1453 legacy_wallmounted = readU8(is);
1454 deSerializeSimpleSoundSpec(sound_footstep, is);
1455 deSerializeSimpleSoundSpec(sound_dig, is);
1456 deSerializeSimpleSoundSpec(sound_dug, is);
1457 rightclickable = readU8(is);
1458 drowning = readU8(is);
1459 leveled = readU8(is);
1460 liquid_range = readU8(is);
1462 throw SerializationError("unsupported ContentFeatures version");
1467 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1469 return m_node_registration_complete;
1473 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1475 m_node_registration_complete = completed;
1479 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1482 if (m_node_registration_complete)
1483 nr->nodeResolveInternal();
1485 m_pending_resolve_callbacks.push_back(nr);
1489 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1491 size_t len = m_pending_resolve_callbacks.size();
1492 for (size_t i = 0; i != len; i++) {
1493 if (nr != m_pending_resolve_callbacks[i])
1497 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1498 m_pending_resolve_callbacks.resize(len);
1506 void CNodeDefManager::runNodeResolveCallbacks()
1508 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1509 NodeResolver *nr = m_pending_resolve_callbacks[i];
1510 nr->nodeResolveInternal();
1513 m_pending_resolve_callbacks.clear();
1517 void CNodeDefManager::resetNodeResolveState()
1519 m_node_registration_complete = false;
1520 m_pending_resolve_callbacks.clear();
1523 void CNodeDefManager::mapNodeboxConnections()
1525 for (u32 i = 0; i < m_content_features.size(); i++) {
1526 ContentFeatures *f = &m_content_features[i];
1527 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1529 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1530 it != f->connects_to.end(); ++it) {
1531 getIds(*it, f->connects_to_ids);
1536 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1538 const ContentFeatures &f1 = get(from);
1540 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1543 // lookup target in connected set
1544 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1547 const ContentFeatures &f2 = get(to);
1549 if ((f2.drawtype == NDT_NODEBOX) && (f1.node_box.type == NODEBOX_CONNECTED))
1550 // ignores actually looking if back connection exists
1551 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1553 // does to node declare usable faces?
1554 if (f2.connect_sides > 0) {
1555 if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
1556 static const u8 rot[33 * 4] = {
1557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1558 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
1559 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
1560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1561 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
1562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1563 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1564 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1565 32, 16, 8, 4 // 32 - left
1567 return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
1569 return (f2.connect_sides & connect_face);
1571 // the target is just a regular node, so connect no matter back connection
1579 NodeResolver::NodeResolver()
1582 m_nodenames_idx = 0;
1583 m_nnlistsizes_idx = 0;
1584 m_resolve_done = false;
1586 m_nodenames.reserve(16);
1587 m_nnlistsizes.reserve(4);
1591 NodeResolver::~NodeResolver()
1593 if (!m_resolve_done && m_ndef)
1594 m_ndef->cancelNodeResolveCallback(this);
1598 void NodeResolver::nodeResolveInternal()
1600 m_nodenames_idx = 0;
1601 m_nnlistsizes_idx = 0;
1604 m_resolve_done = true;
1606 m_nodenames.clear();
1607 m_nnlistsizes.clear();
1611 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1612 const std::string &node_alt, content_t c_fallback)
1614 if (m_nodenames_idx == m_nodenames.size()) {
1615 *result_out = c_fallback;
1616 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1621 std::string name = m_nodenames[m_nodenames_idx++];
1623 bool success = m_ndef->getId(name, c);
1624 if (!success && node_alt != "") {
1626 success = m_ndef->getId(name, c);
1630 errorstream << "NodeResolver: failed to resolve node name '" << name
1631 << "'." << std::endl;
1640 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1641 bool all_required, content_t c_fallback)
1643 bool success = true;
1645 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1646 errorstream << "NodeResolver: no more node lists" << std::endl;
1650 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1653 if (m_nodenames_idx == m_nodenames.size()) {
1654 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1659 std::string &name = m_nodenames[m_nodenames_idx++];
1661 if (name.substr(0,6) != "group:") {
1662 if (m_ndef->getId(name, c)) {
1663 result_out->push_back(c);
1664 } else if (all_required) {
1665 errorstream << "NodeResolver: failed to resolve node name '"
1666 << name << "'." << std::endl;
1667 result_out->push_back(c_fallback);
1671 std::set<content_t> cids;
1672 std::set<content_t>::iterator it;
1673 m_ndef->getIds(name, cids);
1674 for (it = cids.begin(); it != cids.end(); ++it)
1675 result_out->push_back(*it);