From ccd664974ae10331824f5889fa6f3ca909fa421f Mon Sep 17 00:00:00 2001 From: Joshua Bordelon Date: Sun, 11 Jan 2026 15:10:09 -0600 Subject: [PATCH] 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/' as separate properties per library When the scene packer looked for 'libraries/' 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/' 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 --- scene/resources/packed_scene.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 05650a44d0..039dd5eb2c 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -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/" property. + // If we're looking for "libraries/" 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.