Fix animation library serialization compatibility for 4.5 projects

When opening a Godot 4.5 project in 4.6 and saving scenes with editable
children of imported scenes (e.g., .blend files), all animation data was
incorrectly being saved to the .tscn file.

This happened because the AnimationLibrary serialization format changed
between 4.5 and 4.6:
- 4.5: 'libraries' as a single Dictionary property
- 4.6: 'libraries/<name>' as separate properties per library

When the scene packer looked for 'libraries/<name>' in old imported
scenes, it didn't find them (only 'libraries' existed), causing all
animation data to appear as 'overridden' and be saved.

This fix adds backwards compatibility in SceneState::get_property_value()
to check for the old Dictionary format when looking up 'libraries/<name>'
properties. It only applies to nodes that inherit from AnimationMixer,
allowing property comparison to work correctly and preventing animation
data from being duplicated into .tscn files.

Fixes #113037
This commit is contained in:
Joshua Bordelon
2026-01-11 15:10:09 -06:00
parent 5002677a4d
commit ccd664974a

View File

@@ -1560,6 +1560,36 @@ Variant SceneState::get_property_value(int p_node, const StringName &p_property,
return variants[p[i].value];
}
}
#ifndef DISABLE_DEPRECATED
#ifdef TOOLS_ENABLED
// Compatibility: In 4.5 and earlier, AnimationMixer used a single "libraries" Dictionary property.
// In 4.6+, each library is stored as a separate "libraries/<name>" property.
// If we're looking for "libraries/<name>" and didn't find it, check the old format.
String prop_str = p_property.operator String();
if (prop_str.begins_with("libraries/")) {
StringName node_type = get_node_type(p_node);
if (node_type != StringName() && ClassDB::is_parent_class(node_type, SNAME("AnimationMixer"))) {
String library_name = prop_str.get_slicec('/', 1);
static const StringName libraries_sname = "libraries";
for (int i = 0; i < pc; i++) {
if (namep[p[i].name & FLAG_PROP_NAME_MASK] == libraries_sname) {
Variant libs_variant = variants[p[i].value];
if (libs_variant.get_type() == Variant::DICTIONARY) {
Dictionary libs_dict = libs_variant;
if (libs_dict.has(library_name)) {
r_found = true;
r_node_deferred = false;
return libs_dict[library_name];
}
}
break;
}
}
}
}
#endif // TOOLS_ENABLED
#endif // DISABLE_DEPRECATED
}
// Property not found, try on instance.