1
0
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:
DS
2025-12-31 15:19:45 +01:00
committed by GitHub
parent 7a73d37aee
commit 6079d762ce
3 changed files with 12 additions and 23 deletions

View File

@@ -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());
}

View File

@@ -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)

View File

@@ -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;
}
}