mirror of
https://github.com/luanti-org/luanti.git
synced 2026-01-02 19:25:20 +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
|
<< "----" << std::endl
|
||||||
<< "\"" << e.what() << "\"" << std::endl
|
<< "\"" << e.what() << "\"" << std::endl
|
||||||
<< "See debug.txt." << 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;
|
<< std::endl;
|
||||||
m_server->setAsyncFatalError(err.str());
|
m_server->setAsyncFatalError(err.str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,12 +352,6 @@ void MapBlock::correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
|||||||
IGameDef *gamedef)
|
IGameDef *gamedef)
|
||||||
{
|
{
|
||||||
const NodeDefManager *nodedef = gamedef->ndef();
|
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.
|
// Used to cache local to global id lookup.
|
||||||
IdIdMapping &mapping_cache = IdIdMapping::giveClearedThreadLocalInstance();
|
IdIdMapping &mapping_cache = IdIdMapping::giveClearedThreadLocalInstance();
|
||||||
@@ -372,16 +366,16 @@ void MapBlock::correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
|
|||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
if (!nimap->getName(local_id, name)) {
|
if (!nimap->getName(local_id, name)) {
|
||||||
unnamed_contents.insert(local_id);
|
throw SerializationError("MapBlock::correctBlockNodeIds(): "
|
||||||
continue;
|
"Block contains id " + itos(local_id) + " with no name mapping");
|
||||||
}
|
}
|
||||||
|
|
||||||
content_t global_id;
|
content_t global_id;
|
||||||
if (!nodedef->getId(name, global_id)) {
|
if (!nodedef->getId(name, global_id)) {
|
||||||
global_id = gamedef->allocateUnknownNodeId(name);
|
global_id = gamedef->allocateUnknownNodeId(name);
|
||||||
if (global_id == CONTENT_IGNORE) {
|
if (global_id == CONTENT_IGNORE) {
|
||||||
unallocatable_contents.insert(name);
|
throw SerializationError("MapBlock::correctBlockNodeIds(): "
|
||||||
continue;
|
"Could not allocate global id for node name \"" + name + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodes[i].setContent(global_id);
|
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
|
// Save previous node local_id & global_id result
|
||||||
mapping_cache.set(local_id, global_id);
|
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)
|
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];
|
const ContentFeatures &f = m_content_features[id];
|
||||||
if (f.name.empty()) {
|
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;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user