Fix #114582: Replace unknown node types with an 'undefined' node

When loading an unknown node type from a newer Blender version, the node
storage data cannot be properly loaded. Re-saving the file will then
crash if saving with the same node type idname, since new Blender
versions cannot find the expected storage data.

Loading in older versions should replace unknown node types with a dummy
"Undefined" node that will get loaded as `NodeTypeUndefined` in newer
versions as well. Custom node types are exempted from this since they
store all data as generic ID properties and can always be fully
serialized.

Pull Request: https://projects.blender.org/blender/blender/pulls/114803
This commit is contained in:
Lukas Tönne
2023-11-13 16:36:42 +01:00
parent 3cac5c83ec
commit 2bf46b3189

View File

@@ -888,6 +888,29 @@ static void direct_link_node_socket_list(BlendDataReader *reader, ListBase *sock
}
}
/* Build a set of built-in node types to check for known types. */
static blender::Set<int> get_known_node_types_set()
{
blender::Set<int> result;
NODE_TYPES_BEGIN (ntype) {
result.add(ntype->type);
}
NODE_TYPES_END;
return result;
}
static bool can_read_node_type(const int type)
{
/* Can always read custom node types. */
if (type == NODE_CUSTOM) {
return true;
}
/* Check known built-in types. */
static blender::Set<int> known_types = get_known_node_types_set();
return known_types.contains(type);
}
void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
{
/* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs
@@ -946,6 +969,18 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
BLO_read_data_address(reader, &node->prop);
IDP_BlendDataRead(reader, &node->prop);
/* Unknown built-in node types cannot be read reliably, so replace them with 'undefined' type
* nodes. This keeps links and socket names but discards storage an other type-specific data.
*/
if (!can_read_node_type(node->type)) {
node->type = NODE_CUSTOM;
/* This type name is arbitrary, it just has to be unique enough to not match a future node
* idname. Includes the old type identifier for debugging purposes. */
const std::string old_idname = node->idname;
BLI_snprintf(node->idname, sizeof(node->idname), "Undefined[%s]", old_idname.c_str());
continue;
}
if (node->type == CMP_NODE_MOVIEDISTORTION) {
/* Do nothing, this is runtime cache and hence handled by generic code using
* `IDTypeInfo.foreach_cache` callback. */