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 connects_to_ids.clear();
483 for (u16 i = 0; i < connects_to_size; i++)
484 connects_to_ids.insert(readU16(is));
485 connect_sides = readU8(is);
486 }catch(SerializationError &e) {};
493 class CNodeDefManager: public IWritableNodeDefManager {
496 virtual ~CNodeDefManager();
498 virtual IWritableNodeDefManager *clone();
499 inline virtual const ContentFeatures& get(content_t c) const;
500 inline virtual const ContentFeatures& get(const MapNode &n) const;
501 virtual bool getId(const std::string &name, content_t &result) const;
502 virtual content_t getId(const std::string &name) const;
503 virtual bool getIds(const std::string &name, std::set<content_t> &result) const;
504 virtual const ContentFeatures& get(const std::string &name) const;
505 content_t allocateId();
506 virtual content_t set(const std::string &name, const ContentFeatures &def);
507 virtual content_t allocateDummy(const std::string &name);
508 virtual void updateAliases(IItemDefManager *idef);
509 virtual void applyTextureOverrides(const std::string &override_filepath);
510 virtual void updateTextures(IGameDef *gamedef,
511 void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
512 void *progress_cbk_args);
513 void serialize(std::ostream &os, u16 protocol_version) const;
514 void deSerialize(std::istream &is);
516 inline virtual bool getNodeRegistrationStatus() const;
517 inline virtual void setNodeRegistrationStatus(bool completed);
519 virtual void pendNodeResolve(NodeResolver *nr);
520 virtual bool cancelNodeResolveCallback(NodeResolver *nr);
521 virtual void runNodeResolveCallbacks();
522 virtual void resetNodeResolveState();
523 virtual void mapNodeboxConnections();
524 virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
527 void addNameIdMapping(content_t i, std::string name);
529 void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
530 u32 shader_id, bool use_normal_texture, bool backface_culling,
531 u8 alpha, u8 material_type);
534 // Features indexed by id
535 std::vector<ContentFeatures> m_content_features;
537 // A mapping for fast converting back and forth between names and ids
538 NameIdMapping m_name_id_mapping;
540 // Like m_name_id_mapping, but only from names to ids, and includes
541 // item aliases too. Updated by updateAliases()
542 // Note: Not serialized.
544 std::map<std::string, content_t> m_name_id_mapping_with_aliases;
546 // A mapping from groups to a list of content_ts (and their levels)
547 // that belong to it. Necessary for a direct lookup in getIds().
548 // Note: Not serialized.
549 std::map<std::string, GroupItems> m_group_to_items;
551 // Next possibly free id
554 // NodeResolvers to callback once node registration has ended
555 std::vector<NodeResolver *> m_pending_resolve_callbacks;
557 // True when all nodes have been registered
558 bool m_node_registration_complete;
562 CNodeDefManager::CNodeDefManager()
568 CNodeDefManager::~CNodeDefManager()
571 for (u32 i = 0; i < m_content_features.size(); i++) {
572 ContentFeatures *f = &m_content_features[i];
573 for (u32 j = 0; j < 24; j++) {
575 f->mesh_ptr[j]->drop();
582 void CNodeDefManager::clear()
584 m_content_features.clear();
585 m_name_id_mapping.clear();
586 m_name_id_mapping_with_aliases.clear();
587 m_group_to_items.clear();
590 resetNodeResolveState();
592 u32 initial_length = 0;
593 initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
594 initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
595 initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
596 m_content_features.resize(initial_length);
598 // Set CONTENT_UNKNOWN
602 // Insert directly into containers
603 content_t c = CONTENT_UNKNOWN;
604 m_content_features[c] = f;
605 addNameIdMapping(c, f.name);
612 f.drawtype = NDT_AIRLIKE;
613 f.param_type = CPT_LIGHT;
614 f.light_propagates = true;
615 f.sunlight_propagates = true;
619 f.buildable_to = true;
621 f.is_ground_content = true;
622 // Insert directly into containers
623 content_t c = CONTENT_AIR;
624 m_content_features[c] = f;
625 addNameIdMapping(c, f.name);
628 // Set CONTENT_IGNORE
632 f.drawtype = NDT_AIRLIKE;
633 f.param_type = CPT_NONE;
634 f.light_propagates = false;
635 f.sunlight_propagates = false;
639 f.buildable_to = true; // A way to remove accidental CONTENT_IGNOREs
640 f.is_ground_content = true;
641 // Insert directly into containers
642 content_t c = CONTENT_IGNORE;
643 m_content_features[c] = f;
644 addNameIdMapping(c, f.name);
649 IWritableNodeDefManager *CNodeDefManager::clone()
651 CNodeDefManager *mgr = new CNodeDefManager();
657 inline const ContentFeatures& CNodeDefManager::get(content_t c) const
659 return c < m_content_features.size()
660 ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
664 inline const ContentFeatures& CNodeDefManager::get(const MapNode &n) const
666 return get(n.getContent());
670 bool CNodeDefManager::getId(const std::string &name, content_t &result) const
672 std::map<std::string, content_t>::const_iterator
673 i = m_name_id_mapping_with_aliases.find(name);
674 if(i == m_name_id_mapping_with_aliases.end())
681 content_t CNodeDefManager::getId(const std::string &name) const
683 content_t id = CONTENT_IGNORE;
689 bool CNodeDefManager::getIds(const std::string &name,
690 std::set<content_t> &result) const
692 //TimeTaker t("getIds", NULL, PRECISION_MICRO);
693 if (name.substr(0,6) != "group:") {
694 content_t id = CONTENT_IGNORE;
695 bool exists = getId(name, id);
700 std::string group = name.substr(6);
702 std::map<std::string, GroupItems>::const_iterator
703 i = m_group_to_items.find(group);
704 if (i == m_group_to_items.end())
707 const GroupItems &items = i->second;
708 for (GroupItems::const_iterator j = items.begin();
709 j != items.end(); ++j) {
710 if ((*j).second != 0)
711 result.insert((*j).first);
713 //printf("getIds: %dus\n", t.stop());
718 const ContentFeatures& CNodeDefManager::get(const std::string &name) const
720 content_t id = CONTENT_UNKNOWN;
726 // returns CONTENT_IGNORE if no free ID found
727 content_t CNodeDefManager::allocateId()
729 for (content_t id = m_next_id;
730 id >= m_next_id; // overflow?
732 while (id >= m_content_features.size()) {
733 m_content_features.push_back(ContentFeatures());
735 const ContentFeatures &f = m_content_features[id];
741 // If we arrive here, an overflow occurred in id.
742 // That means no ID was found
743 return CONTENT_IGNORE;
747 // IWritableNodeDefManager
748 content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
752 assert(name == def.name);
754 // Don't allow redefining ignore (but allow air and unknown)
755 if (name == "ignore") {
756 warningstream << "NodeDefManager: Ignoring "
757 "CONTENT_IGNORE redefinition"<<std::endl;
758 return CONTENT_IGNORE;
761 content_t id = CONTENT_IGNORE;
762 if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
765 if (id == CONTENT_IGNORE) {
766 warningstream << "NodeDefManager: Absolute "
767 "limit reached" << std::endl;
768 return CONTENT_IGNORE;
770 assert(id != CONTENT_IGNORE);
771 addNameIdMapping(id, name);
773 m_content_features[id] = def;
774 verbosestream << "NodeDefManager: registering content id \"" << id
775 << "\": name=\"" << def.name << "\""<<std::endl;
777 // Add this content to the list of all groups it belongs to
778 // FIXME: This should remove a node from groups it no longer
779 // belongs to when a node is re-registered
780 for (ItemGroupList::const_iterator i = def.groups.begin();
781 i != def.groups.end(); ++i) {
782 std::string group_name = i->first;
784 std::map<std::string, GroupItems>::iterator
785 j = m_group_to_items.find(group_name);
786 if (j == m_group_to_items.end()) {
787 m_group_to_items[group_name].push_back(
788 std::make_pair(id, i->second));
790 GroupItems &items = j->second;
791 items.push_back(std::make_pair(id, i->second));
798 content_t CNodeDefManager::allocateDummy(const std::string &name)
800 assert(name != ""); // Pre-condition
807 void CNodeDefManager::updateAliases(IItemDefManager *idef)
809 std::set<std::string> all = idef->getAll();
810 m_name_id_mapping_with_aliases.clear();
811 for (std::set<std::string>::iterator
812 i = all.begin(); i != all.end(); ++i) {
813 std::string name = *i;
814 std::string convert_to = idef->getAlias(name);
816 if (m_name_id_mapping.getId(convert_to, id)) {
817 m_name_id_mapping_with_aliases.insert(
818 std::make_pair(name, id));
823 void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath)
825 infostream << "CNodeDefManager::applyTextureOverrides(): Applying "
826 "overrides to textures from " << override_filepath << std::endl;
828 std::ifstream infile(override_filepath.c_str());
831 while (std::getline(infile, line)) {
833 if (trim(line) == "")
835 std::vector<std::string> splitted = str_split(line, ' ');
836 if (splitted.size() != 3) {
837 errorstream << override_filepath
838 << ":" << line_c << " Could not apply texture override \""
839 << line << "\": Syntax error" << std::endl;
844 if (!getId(splitted[0], id)) {
845 errorstream << override_filepath
846 << ":" << line_c << " Could not apply texture override \""
847 << line << "\": Unknown node \""
848 << splitted[0] << "\"" << std::endl;
852 ContentFeatures &nodedef = m_content_features[id];
854 if (splitted[1] == "top")
855 nodedef.tiledef[0].name = splitted[2];
856 else if (splitted[1] == "bottom")
857 nodedef.tiledef[1].name = splitted[2];
858 else if (splitted[1] == "right")
859 nodedef.tiledef[2].name = splitted[2];
860 else if (splitted[1] == "left")
861 nodedef.tiledef[3].name = splitted[2];
862 else if (splitted[1] == "back")
863 nodedef.tiledef[4].name = splitted[2];
864 else if (splitted[1] == "front")
865 nodedef.tiledef[5].name = splitted[2];
866 else if (splitted[1] == "all" || splitted[1] == "*")
867 for (int i = 0; i < 6; i++)
868 nodedef.tiledef[i].name = splitted[2];
869 else if (splitted[1] == "sides")
870 for (int i = 2; i < 6; i++)
871 nodedef.tiledef[i].name = splitted[2];
873 errorstream << override_filepath
874 << ":" << line_c << " Could not apply texture override \""
875 << line << "\": Unknown node side \""
876 << splitted[1] << "\"" << std::endl;
882 void CNodeDefManager::updateTextures(IGameDef *gamedef,
883 void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
884 void *progress_callback_args)
887 infostream << "CNodeDefManager::updateTextures(): Updating "
888 "textures in node definitions" << std::endl;
889 ITextureSource *tsrc = gamedef->tsrc();
890 IShaderSource *shdsrc = gamedef->getShaderSource();
891 scene::ISceneManager* smgr = gamedef->getSceneManager();
892 scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
894 bool connected_glass = g_settings->getBool("connected_glass");
895 bool opaque_water = g_settings->getBool("opaque_water");
896 bool enable_shaders = g_settings->getBool("enable_shaders");
897 bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
898 bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
899 bool enable_mesh_cache = g_settings->getBool("enable_mesh_cache");
900 bool enable_minimap = g_settings->getBool("enable_minimap");
901 std::string leaves_style = g_settings->get("leaves_style");
903 bool use_normal_texture = enable_shaders &&
904 (enable_bumpmapping || enable_parallax_occlusion);
906 u32 size = m_content_features.size();
908 for (u32 i = 0; i < size; i++) {
909 ContentFeatures *f = &m_content_features[i];
911 // minimap pixel color - the average color of a texture
912 if (enable_minimap && f->tiledef[0].name != "")
913 f->minimap_color = tsrc->getTextureAverageColor(f->tiledef[0].name);
915 // Figure out the actual tiles to use
917 for (u32 j = 0; j < 6; j++) {
918 tiledef[j] = f->tiledef[j];
919 if (tiledef[j].name == "")
920 tiledef[j].name = "unknown_node.png";
923 bool is_liquid = false;
924 bool is_water_surface = false;
926 u8 material_type = (f->alpha == 255) ?
927 TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
929 switch (f->drawtype) {
938 assert(f->liquid_type == LIQUID_SOURCE);
944 case NDT_FLOWINGLIQUID:
945 assert(f->liquid_type == LIQUID_FLOWING);
953 f->visual_solidness = 1;
955 case NDT_GLASSLIKE_FRAMED:
957 f->visual_solidness = 1;
959 case NDT_GLASSLIKE_FRAMED_OPTIONAL:
961 f->visual_solidness = 1;
962 f->drawtype = connected_glass ? NDT_GLASSLIKE_FRAMED : NDT_GLASSLIKE;
966 f->visual_solidness = 1;
968 case NDT_ALLFACES_OPTIONAL:
969 if (leaves_style == "fancy") {
970 f->drawtype = NDT_ALLFACES;
972 f->visual_solidness = 1;
973 } else if (leaves_style == "simple") {
974 for (u32 j = 0; j < 6; j++) {
975 if (f->tiledef_special[j].name != "")
976 tiledef[j].name = f->tiledef_special[j].name;
978 f->drawtype = NDT_GLASSLIKE;
980 f->visual_solidness = 1;
982 f->drawtype = NDT_NORMAL;
984 for (u32 i = 0; i < 6; i++)
985 tiledef[i].name += std::string("^[noalpha");
988 material_type = TILE_MATERIAL_WAVING_LEAVES;
993 material_type = TILE_MATERIAL_WAVING_PLANTS;
1011 material_type = (f->alpha == 255) ?
1012 TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
1013 if (f->name == "default:water_source")
1014 is_water_surface = true;
1018 for (u16 j = 0; j < 6; j++) {
1019 tile_shader[j] = shdsrc->getShader("nodes_shader",
1020 material_type, f->drawtype);
1023 if (is_water_surface) {
1024 tile_shader[0] = shdsrc->getShader("water_surface_shader",
1025 material_type, f->drawtype);
1028 // Tiles (fill in f->tiles[])
1029 for (u16 j = 0; j < 6; j++) {
1030 fillTileAttribs(tsrc, &f->tiles[j], &tiledef[j], tile_shader[j],
1031 use_normal_texture, f->tiledef[j].backface_culling, f->alpha, material_type);
1034 // Special tiles (fill in f->special_tiles[])
1035 for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
1036 fillTileAttribs(tsrc, &f->special_tiles[j], &f->tiledef_special[j],
1037 tile_shader[j], use_normal_texture,
1038 f->tiledef_special[j].backface_culling, f->alpha, material_type);
1041 if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
1042 // Meshnode drawtype
1043 // Read the mesh and apply scale
1044 f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
1045 if (f->mesh_ptr[0]){
1046 v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
1047 scaleMesh(f->mesh_ptr[0], scale);
1048 recalculateBoundingBox(f->mesh_ptr[0]);
1049 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1051 } else if ((f->drawtype == NDT_NODEBOX) &&
1052 ((f->node_box.type == NODEBOX_REGULAR) ||
1053 (f->node_box.type == NODEBOX_FIXED)) &&
1054 (!f->node_box.fixed.empty())) {
1055 //Convert regular nodebox nodes to meshnodes
1056 //Change the drawtype and apply scale
1057 f->drawtype = NDT_MESH;
1058 f->mesh_ptr[0] = convertNodeboxesToMesh(f->node_box.fixed);
1059 v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
1060 scaleMesh(f->mesh_ptr[0], scale);
1061 recalculateBoundingBox(f->mesh_ptr[0]);
1062 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1065 //Cache 6dfacedir and wallmounted rotated clones of meshes
1066 if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
1067 for (u16 j = 1; j < 24; j++) {
1068 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1069 rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
1070 recalculateBoundingBox(f->mesh_ptr[j]);
1071 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1073 } else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
1074 static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
1075 for (u16 j = 1; j < 6; j++) {
1076 f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
1077 rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
1078 recalculateBoundingBox(f->mesh_ptr[j]);
1079 meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
1081 rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
1082 recalculateBoundingBox(f->mesh_ptr[0]);
1083 meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);
1086 progress_callback(progress_callback_args, i, size);
1093 void CNodeDefManager::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
1094 TileDef *tiledef, u32 shader_id, bool use_normal_texture,
1095 bool backface_culling, u8 alpha, u8 material_type)
1097 tile->shader_id = shader_id;
1098 tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
1099 tile->alpha = alpha;
1100 tile->material_type = material_type;
1102 // Normal texture and shader flags texture
1103 if (use_normal_texture) {
1104 tile->normal_texture = tsrc->getNormalTexture(tiledef->name);
1106 tile->flags_texture = tsrc->getShaderFlagsTexture(tile->normal_texture ? true : false);
1109 tile->material_flags = 0;
1110 if (backface_culling)
1111 tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
1112 if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
1113 tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1114 if (tiledef->tileable_horizontal)
1115 tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
1116 if (tiledef->tileable_vertical)
1117 tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
1119 // Animation parameters
1120 int frame_count = 1;
1121 if (tile->material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
1122 // Get texture size to determine frame count by aspect ratio
1123 v2u32 size = tile->texture->getOriginalSize();
1124 int frame_height = (float)size.X /
1125 (float)tiledef->animation.aspect_w *
1126 (float)tiledef->animation.aspect_h;
1127 frame_count = size.Y / frame_height;
1128 int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
1129 tile->animation_frame_count = frame_count;
1130 tile->animation_frame_length_ms = frame_length_ms;
1133 if (frame_count == 1) {
1134 tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
1136 std::ostringstream os(std::ios::binary);
1137 tile->frames.resize(frame_count);
1139 for (int i = 0; i < frame_count; i++) {
1144 os << tiledef->name << "^[verticalframe:"
1145 << frame_count << ":" << i;
1147 frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
1148 if (tile->normal_texture)
1149 frame.normal_texture = tsrc->getNormalTexture(os.str());
1150 frame.flags_texture = tile->flags_texture;
1151 tile->frames[i] = frame;
1158 void CNodeDefManager::serialize(std::ostream &os, u16 protocol_version) const
1160 writeU8(os, 1); // version
1162 std::ostringstream os2(std::ios::binary);
1163 for (u32 i = 0; i < m_content_features.size(); i++) {
1164 if (i == CONTENT_IGNORE || i == CONTENT_AIR
1165 || i == CONTENT_UNKNOWN)
1167 const ContentFeatures *f = &m_content_features[i];
1171 // Wrap it in a string to allow different lengths without
1172 // strict version incompatibilities
1173 std::ostringstream wrapper_os(std::ios::binary);
1174 f->serialize(wrapper_os, protocol_version);
1175 os2<<serializeString(wrapper_os.str());
1177 // must not overflow
1178 u16 next = count + 1;
1179 FATAL_ERROR_IF(next < count, "Overflow");
1182 writeU16(os, count);
1183 os << serializeLongString(os2.str());
1187 void CNodeDefManager::deSerialize(std::istream &is)
1190 int version = readU8(is);
1192 throw SerializationError("unsupported NodeDefinitionManager version");
1193 u16 count = readU16(is);
1194 std::istringstream is2(deSerializeLongString(is), std::ios::binary);
1196 for (u16 n = 0; n < count; n++) {
1197 u16 i = readU16(is2);
1199 // Read it from the string wrapper
1200 std::string wrapper = deSerializeString(is2);
1201 std::istringstream wrapper_is(wrapper, std::ios::binary);
1202 f.deSerialize(wrapper_is);
1204 // Check error conditions
1205 if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
1206 warningstream << "NodeDefManager::deSerialize(): "
1207 "not changing builtin node " << i << std::endl;
1211 warningstream << "NodeDefManager::deSerialize(): "
1212 "received empty name" << std::endl;
1218 if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
1219 warningstream << "NodeDefManager::deSerialize(): "
1220 "already defined with different ID: " << f.name << std::endl;
1224 // All is ok, add node definition with the requested ID
1225 if (i >= m_content_features.size())
1226 m_content_features.resize((u32)(i) + 1);
1227 m_content_features[i] = f;
1228 addNameIdMapping(i, f.name);
1229 verbosestream << "deserialized " << f.name << std::endl;
1234 void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
1236 m_name_id_mapping.set(i, name);
1237 m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
1241 IWritableNodeDefManager *createNodeDefManager()
1243 return new CNodeDefManager();
1247 //// Serialization of old ContentFeatures formats
1248 void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
1250 if (protocol_version == 13)
1252 writeU8(os, 5); // version
1253 os<<serializeString(name);
1254 writeU16(os, groups.size());
1255 for (ItemGroupList::const_iterator
1256 i = groups.begin(); i != groups.end(); ++i) {
1257 os<<serializeString(i->first);
1258 writeS16(os, i->second);
1260 writeU8(os, drawtype);
1261 writeF1000(os, visual_scale);
1263 for (u32 i = 0; i < 6; i++)
1264 tiledef[i].serialize(os, protocol_version);
1265 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1267 for (u32 i = 0; i < 2; i++)
1268 tiledef_special[i].serialize(os, protocol_version);
1270 writeU8(os, post_effect_color.getAlpha());
1271 writeU8(os, post_effect_color.getRed());
1272 writeU8(os, post_effect_color.getGreen());
1273 writeU8(os, post_effect_color.getBlue());
1274 writeU8(os, param_type);
1275 writeU8(os, param_type_2);
1276 writeU8(os, is_ground_content);
1277 writeU8(os, light_propagates);
1278 writeU8(os, sunlight_propagates);
1279 writeU8(os, walkable);
1280 writeU8(os, pointable);
1281 writeU8(os, diggable);
1282 writeU8(os, climbable);
1283 writeU8(os, buildable_to);
1284 os<<serializeString(""); // legacy: used to be metadata_name
1285 writeU8(os, liquid_type);
1286 os<<serializeString(liquid_alternative_flowing);
1287 os<<serializeString(liquid_alternative_source);
1288 writeU8(os, liquid_viscosity);
1289 writeU8(os, light_source);
1290 writeU32(os, damage_per_second);
1291 node_box.serialize(os, protocol_version);
1292 selection_box.serialize(os, protocol_version);
1293 writeU8(os, legacy_facedir_simple);
1294 writeU8(os, legacy_wallmounted);
1295 serializeSimpleSoundSpec(sound_footstep, os);
1296 serializeSimpleSoundSpec(sound_dig, os);
1297 serializeSimpleSoundSpec(sound_dug, os);
1299 else if (protocol_version > 13 && protocol_version < 24) {
1300 writeU8(os, 6); // version
1301 os<<serializeString(name);
1302 writeU16(os, groups.size());
1303 for (ItemGroupList::const_iterator
1304 i = groups.begin(); i != groups.end(); ++i) {
1305 os<<serializeString(i->first);
1306 writeS16(os, i->second);
1308 writeU8(os, drawtype);
1309 writeF1000(os, visual_scale);
1311 for (u32 i = 0; i < 6; i++)
1312 tiledef[i].serialize(os, protocol_version);
1313 //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24
1315 for (u32 i = 0; i < 2; i++)
1316 tiledef_special[i].serialize(os, protocol_version);
1318 writeU8(os, post_effect_color.getAlpha());
1319 writeU8(os, post_effect_color.getRed());
1320 writeU8(os, post_effect_color.getGreen());
1321 writeU8(os, post_effect_color.getBlue());
1322 writeU8(os, param_type);
1323 writeU8(os, param_type_2);
1324 writeU8(os, is_ground_content);
1325 writeU8(os, light_propagates);
1326 writeU8(os, sunlight_propagates);
1327 writeU8(os, walkable);
1328 writeU8(os, pointable);
1329 writeU8(os, diggable);
1330 writeU8(os, climbable);
1331 writeU8(os, buildable_to);
1332 os<<serializeString(""); // legacy: used to be metadata_name
1333 writeU8(os, liquid_type);
1334 os<<serializeString(liquid_alternative_flowing);
1335 os<<serializeString(liquid_alternative_source);
1336 writeU8(os, liquid_viscosity);
1337 writeU8(os, liquid_renewable);
1338 writeU8(os, light_source);
1339 writeU32(os, damage_per_second);
1340 node_box.serialize(os, protocol_version);
1341 selection_box.serialize(os, protocol_version);
1342 writeU8(os, legacy_facedir_simple);
1343 writeU8(os, legacy_wallmounted);
1344 serializeSimpleSoundSpec(sound_footstep, os);
1345 serializeSimpleSoundSpec(sound_dig, os);
1346 serializeSimpleSoundSpec(sound_dug, os);
1347 writeU8(os, rightclickable);
1348 writeU8(os, drowning);
1349 writeU8(os, leveled);
1350 writeU8(os, liquid_range);
1352 throw SerializationError("ContentFeatures::serialize(): "
1353 "Unsupported version requested");
1356 void ContentFeatures::deSerializeOld(std::istream &is, int version)
1358 if (version == 5) // In PROTOCOL_VERSION 13
1360 name = deSerializeString(is);
1362 u32 groups_size = readU16(is);
1363 for(u32 i=0; i<groups_size; i++){
1364 std::string name = deSerializeString(is);
1365 int value = readS16(is);
1366 groups[name] = value;
1368 drawtype = (enum NodeDrawType)readU8(is);
1370 visual_scale = readF1000(is);
1371 if (readU8(is) != 6)
1372 throw SerializationError("unsupported tile count");
1373 for (u32 i = 0; i < 6; i++)
1374 tiledef[i].deSerialize(is, version, drawtype);
1375 if (readU8(is) != CF_SPECIAL_COUNT)
1376 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1377 for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
1378 tiledef_special[i].deSerialize(is, version, drawtype);
1380 post_effect_color.setAlpha(readU8(is));
1381 post_effect_color.setRed(readU8(is));
1382 post_effect_color.setGreen(readU8(is));
1383 post_effect_color.setBlue(readU8(is));
1384 param_type = (enum ContentParamType)readU8(is);
1385 param_type_2 = (enum ContentParamType2)readU8(is);
1386 is_ground_content = readU8(is);
1387 light_propagates = readU8(is);
1388 sunlight_propagates = readU8(is);
1389 walkable = readU8(is);
1390 pointable = readU8(is);
1391 diggable = readU8(is);
1392 climbable = readU8(is);
1393 buildable_to = readU8(is);
1394 deSerializeString(is); // legacy: used to be metadata_name
1395 liquid_type = (enum LiquidType)readU8(is);
1396 liquid_alternative_flowing = deSerializeString(is);
1397 liquid_alternative_source = deSerializeString(is);
1398 liquid_viscosity = readU8(is);
1399 light_source = readU8(is);
1400 damage_per_second = readU32(is);
1401 node_box.deSerialize(is);
1402 selection_box.deSerialize(is);
1403 legacy_facedir_simple = readU8(is);
1404 legacy_wallmounted = readU8(is);
1405 deSerializeSimpleSoundSpec(sound_footstep, is);
1406 deSerializeSimpleSoundSpec(sound_dig, is);
1407 deSerializeSimpleSoundSpec(sound_dug, is);
1408 } else if (version == 6) {
1409 name = deSerializeString(is);
1411 u32 groups_size = readU16(is);
1412 for (u32 i = 0; i < groups_size; i++) {
1413 std::string name = deSerializeString(is);
1414 int value = readS16(is);
1415 groups[name] = value;
1417 drawtype = (enum NodeDrawType)readU8(is);
1418 visual_scale = readF1000(is);
1419 if (readU8(is) != 6)
1420 throw SerializationError("unsupported tile count");
1421 for (u32 i = 0; i < 6; i++)
1422 tiledef[i].deSerialize(is, version, drawtype);
1423 // CF_SPECIAL_COUNT in version 6 = 2
1424 if (readU8(is) != 2)
1425 throw SerializationError("unsupported CF_SPECIAL_COUNT");
1426 for (u32 i = 0; i < 2; i++)
1427 tiledef_special[i].deSerialize(is, version, drawtype);
1429 post_effect_color.setAlpha(readU8(is));
1430 post_effect_color.setRed(readU8(is));
1431 post_effect_color.setGreen(readU8(is));
1432 post_effect_color.setBlue(readU8(is));
1433 param_type = (enum ContentParamType)readU8(is);
1434 param_type_2 = (enum ContentParamType2)readU8(is);
1435 is_ground_content = readU8(is);
1436 light_propagates = readU8(is);
1437 sunlight_propagates = readU8(is);
1438 walkable = readU8(is);
1439 pointable = readU8(is);
1440 diggable = readU8(is);
1441 climbable = readU8(is);
1442 buildable_to = readU8(is);
1443 deSerializeString(is); // legacy: used to be metadata_name
1444 liquid_type = (enum LiquidType)readU8(is);
1445 liquid_alternative_flowing = deSerializeString(is);
1446 liquid_alternative_source = deSerializeString(is);
1447 liquid_viscosity = readU8(is);
1448 liquid_renewable = readU8(is);
1449 light_source = readU8(is);
1450 damage_per_second = readU32(is);
1451 node_box.deSerialize(is);
1452 selection_box.deSerialize(is);
1453 legacy_facedir_simple = readU8(is);
1454 legacy_wallmounted = readU8(is);
1455 deSerializeSimpleSoundSpec(sound_footstep, is);
1456 deSerializeSimpleSoundSpec(sound_dig, is);
1457 deSerializeSimpleSoundSpec(sound_dug, is);
1458 rightclickable = readU8(is);
1459 drowning = readU8(is);
1460 leveled = readU8(is);
1461 liquid_range = readU8(is);
1463 throw SerializationError("unsupported ContentFeatures version");
1468 inline bool CNodeDefManager::getNodeRegistrationStatus() const
1470 return m_node_registration_complete;
1474 inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
1476 m_node_registration_complete = completed;
1480 void CNodeDefManager::pendNodeResolve(NodeResolver *nr)
1483 if (m_node_registration_complete)
1484 nr->nodeResolveInternal();
1486 m_pending_resolve_callbacks.push_back(nr);
1490 bool CNodeDefManager::cancelNodeResolveCallback(NodeResolver *nr)
1492 size_t len = m_pending_resolve_callbacks.size();
1493 for (size_t i = 0; i != len; i++) {
1494 if (nr != m_pending_resolve_callbacks[i])
1498 m_pending_resolve_callbacks[i] = m_pending_resolve_callbacks[len];
1499 m_pending_resolve_callbacks.resize(len);
1507 void CNodeDefManager::runNodeResolveCallbacks()
1509 for (size_t i = 0; i != m_pending_resolve_callbacks.size(); i++) {
1510 NodeResolver *nr = m_pending_resolve_callbacks[i];
1511 nr->nodeResolveInternal();
1514 m_pending_resolve_callbacks.clear();
1518 void CNodeDefManager::resetNodeResolveState()
1520 m_node_registration_complete = false;
1521 m_pending_resolve_callbacks.clear();
1524 void CNodeDefManager::mapNodeboxConnections()
1526 for (u32 i = 0; i < m_content_features.size(); i++) {
1527 ContentFeatures *f = &m_content_features[i];
1528 if ((f->drawtype != NDT_NODEBOX) || (f->node_box.type != NODEBOX_CONNECTED))
1530 for (std::vector<std::string>::iterator it = f->connects_to.begin();
1531 it != f->connects_to.end(); ++it) {
1532 getIds(*it, f->connects_to_ids);
1537 bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
1539 const ContentFeatures &f1 = get(from);
1541 if ((f1.drawtype != NDT_NODEBOX) || (f1.node_box.type != NODEBOX_CONNECTED))
1544 // lookup target in connected set
1545 if (f1.connects_to_ids.find(to.param0) == f1.connects_to_ids.end())
1548 const ContentFeatures &f2 = get(to);
1550 if ((f2.drawtype == NDT_NODEBOX) && (f2.node_box.type == NODEBOX_CONNECTED))
1551 // ignores actually looking if back connection exists
1552 return (f2.connects_to_ids.find(from.param0) != f2.connects_to_ids.end());
1554 // does to node declare usable faces?
1555 if (f2.connect_sides > 0) {
1556 if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
1557 static const u8 rot[33 * 4] = {
1558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1559 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
1560 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
1561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1562 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1566 32, 16, 8, 4 // 32 - left
1568 return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
1570 return (f2.connect_sides & connect_face);
1572 // the target is just a regular node, so connect no matter back connection
1580 NodeResolver::NodeResolver()
1583 m_nodenames_idx = 0;
1584 m_nnlistsizes_idx = 0;
1585 m_resolve_done = false;
1587 m_nodenames.reserve(16);
1588 m_nnlistsizes.reserve(4);
1592 NodeResolver::~NodeResolver()
1594 if (!m_resolve_done && m_ndef)
1595 m_ndef->cancelNodeResolveCallback(this);
1599 void NodeResolver::nodeResolveInternal()
1601 m_nodenames_idx = 0;
1602 m_nnlistsizes_idx = 0;
1605 m_resolve_done = true;
1607 m_nodenames.clear();
1608 m_nnlistsizes.clear();
1612 bool NodeResolver::getIdFromNrBacklog(content_t *result_out,
1613 const std::string &node_alt, content_t c_fallback)
1615 if (m_nodenames_idx == m_nodenames.size()) {
1616 *result_out = c_fallback;
1617 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1622 std::string name = m_nodenames[m_nodenames_idx++];
1624 bool success = m_ndef->getId(name, c);
1625 if (!success && node_alt != "") {
1627 success = m_ndef->getId(name, c);
1631 errorstream << "NodeResolver: failed to resolve node name '" << name
1632 << "'." << std::endl;
1641 bool NodeResolver::getIdsFromNrBacklog(std::vector<content_t> *result_out,
1642 bool all_required, content_t c_fallback)
1644 bool success = true;
1646 if (m_nnlistsizes_idx == m_nnlistsizes.size()) {
1647 errorstream << "NodeResolver: no more node lists" << std::endl;
1651 size_t length = m_nnlistsizes[m_nnlistsizes_idx++];
1654 if (m_nodenames_idx == m_nodenames.size()) {
1655 errorstream << "NodeResolver: no more nodes in list" << std::endl;
1660 std::string &name = m_nodenames[m_nodenames_idx++];
1662 if (name.substr(0,6) != "group:") {
1663 if (m_ndef->getId(name, c)) {
1664 result_out->push_back(c);
1665 } else if (all_required) {
1666 errorstream << "NodeResolver: failed to resolve node name '"
1667 << name << "'." << std::endl;
1668 result_out->push_back(c_fallback);
1672 std::set<content_t> cids;
1673 std::set<content_t>::iterator it;
1674 m_ndef->getIds(name, cids);
1675 for (it = cids.begin(); it != cids.end(); ++it)
1676 result_out->push_back(*it);