mirror of
https://github.com/luanti-org/luanti.git
synced 2026-01-01 02:45:19 +01:00
Fix corner case when unknown node ids run out (#16790)
* Fix `NodeDefManager::allocateId()` not terminating after overflow * MapBlock::correctBlockNodeIds(): Do not ignore errors Ignoring would lead to information loss, as the local ids were not translated, so they were replaced by different nodes. There is `ignore_world_load_errors` to ignore errors. * Do not advertise without warning for ignore_world_load_errors
This commit is contained in:
@@ -788,7 +788,8 @@ void *EmergeThread::run()
|
||||
<< "----" << std::endl
|
||||
<< "\"" << e.what() << "\"" << std::endl
|
||||
<< "See debug.txt." << std::endl
|
||||
<< "You can ignore this using [ignore_world_load_errors = true]."
|
||||
<< "This can be ignored using the `ignore_world_load_errors` setting. "
|
||||
<< "But it will also destroy stuff in the affected MapBlocks, do not use."
|
||||
<< std::endl;
|
||||
m_server->setAsyncFatalError(err.str());
|
||||
}
|
||||
|
||||
@@ -352,12 +352,6 @@ void MapBlock::correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
||||
IGameDef *gamedef)
|
||||
{
|
||||
const NodeDefManager *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::unordered_set<content_t> unnamed_contents;
|
||||
std::unordered_set<std::string> unallocatable_contents;
|
||||
|
||||
// Used to cache local to global id lookup.
|
||||
IdIdMapping &mapping_cache = IdIdMapping::giveClearedThreadLocalInstance();
|
||||
@@ -372,16 +366,16 @@ void MapBlock::correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
||||
|
||||
std::string name;
|
||||
if (!nimap->getName(local_id, name)) {
|
||||
unnamed_contents.insert(local_id);
|
||||
continue;
|
||||
throw SerializationError("MapBlock::correctBlockNodeIds(): "
|
||||
"Block contains id " + itos(local_id) + " with no name mapping");
|
||||
}
|
||||
|
||||
content_t global_id;
|
||||
if (!nodedef->getId(name, global_id)) {
|
||||
global_id = gamedef->allocateUnknownNodeId(name);
|
||||
if (global_id == CONTENT_IGNORE) {
|
||||
unallocatable_contents.insert(name);
|
||||
continue;
|
||||
throw SerializationError("MapBlock::correctBlockNodeIds(): "
|
||||
"Could not allocate global id for node name \"" + name + "\"");
|
||||
}
|
||||
}
|
||||
nodes[i].setContent(global_id);
|
||||
@@ -389,17 +383,6 @@ void MapBlock::correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
||||
// Save previous node local_id & global_id result
|
||||
mapping_cache.set(local_id, global_id);
|
||||
}
|
||||
|
||||
for (const content_t c: unnamed_contents) {
|
||||
errorstream << "correctBlockNodeIds(): IGNORING ERROR: "
|
||||
<< "Block contains id " << c
|
||||
<< " with no name mapping" << std::endl;
|
||||
}
|
||||
for (const std::string &node_name: unallocatable_contents) {
|
||||
errorstream << "correctBlockNodeIds(): IGNORING ERROR: "
|
||||
<< "Could not allocate global id for node name \""
|
||||
<< node_name << "\"" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level)
|
||||
|
||||
@@ -794,7 +794,12 @@ content_t NodeDefManager::allocateId()
|
||||
}
|
||||
const ContentFeatures &f = m_content_features[id];
|
||||
if (f.name.empty()) {
|
||||
m_next_id = id + 1;
|
||||
// use saturating add, to avoid overflow of m_next_id, which would
|
||||
// make the loop not terminate (loop cond id >= 0 is always true)
|
||||
if (id < CONTENT_MAX)
|
||||
m_next_id = id + 1;
|
||||
else
|
||||
m_next_id = CONTENT_MAX;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user