+// List relevant id-name pairs for ids in the block using nodedef
+// Renumbers the content IDs (starting at 0 and incrementing
+// use static memory requires about 65535 * sizeof(int) ram in order to be
+// sure we can handle all content ids. But it's absolutely worth it as it's
+// a speedup of 4 for one of the major time consuming functions on storing
+// mapblocks.
+static content_t getBlockNodeIdMapping_mapping[USHRT_MAX + 1];
+static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes,
+ INodeDefManager *nodedef)
+{
+ memset(getBlockNodeIdMapping_mapping, 0xFF, (USHRT_MAX + 1) * sizeof(content_t));
+
+ std::set<content_t> unknown_contents;
+ content_t id_counter = 0;
+ for (u32 i = 0; i < MapBlock::nodecount; i++) {
+ content_t global_id = nodes[i].getContent();
+ content_t id = CONTENT_IGNORE;
+
+ // Try to find an existing mapping
+ if (getBlockNodeIdMapping_mapping[global_id] != 0xFFFF) {
+ id = getBlockNodeIdMapping_mapping[global_id];
+ }
+ else
+ {
+ // We have to assign a new mapping
+ id = id_counter++;
+ getBlockNodeIdMapping_mapping[global_id] = id;
+
+ const ContentFeatures &f = nodedef->get(global_id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(global_id);
+ else
+ nimap->set(id, name);
+ }
+
+ // Update the MapNode
+ nodes[i].setContent(id);
+ }
+ for(std::set<content_t>::const_iterator
+ i = unknown_contents.begin();
+ i != unknown_contents.end(); ++i){
+ errorstream<<"getBlockNodeIdMapping(): IGNORING ERROR: "
+ <<"Name for node id "<<(*i)<<" not known"<<std::endl;
+ }
+}
+// Correct ids in the block to match nodedef based on names.
+// Unknown ones are added to nodedef.
+// Will not update itself to match id-name pairs in nodedef.
+static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
+ IGameDef *gamedef)
+{
+ INodeDefManager *nodedef = gamedef->ndef();
+ // This means the block contains incorrect ids, and we contain
+ // the information to convert those to names.
+ // nodedef contains information to convert our names to globally
+ // correct ids.
+ std::set<content_t> unnamed_contents;
+ std::set<std::string> unallocatable_contents;
+ for (u32 i = 0; i < MapBlock::nodecount; i++) {
+ content_t local_id = nodes[i].getContent();
+ std::string name;
+ bool found = nimap->getName(local_id, name);
+ if(!found){
+ unnamed_contents.insert(local_id);
+ continue;
+ }
+ content_t global_id;
+ found = nodedef->getId(name, global_id);
+ if(!found){
+ global_id = gamedef->allocateUnknownNodeId(name);
+ if(global_id == CONTENT_IGNORE){
+ unallocatable_contents.insert(name);
+ continue;
+ }
+ }
+ nodes[i].setContent(global_id);
+ }
+ for(std::set<content_t>::const_iterator
+ i = unnamed_contents.begin();
+ i != unnamed_contents.end(); ++i){
+ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
+ <<"Block contains id "<<(*i)
+ <<" with no name mapping"<<std::endl;
+ }
+ for(std::set<std::string>::const_iterator
+ i = unallocatable_contents.begin();
+ i != unallocatable_contents.end(); ++i){
+ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
+ <<"Could not allocate global id for node name \""
+ <<(*i)<<"\""<<std::endl;
+ }
+}