Fix #121349: Baking adds keys on custom properties that are non-keyable
When keying custom properties that are defined by an addon, you can't use square brackets. The GUI buttons already reflect that. The baking code and the keyframe insertion code didn't respect that and so were able to key properties that are defined as non-keyable. ## Solutions I've solved the issue on the C++ side by resolving the path twice, once without and in case that didn't work the second time with brackets. While that does solve the issue this feels really dirty and I feel like I am misusing the system here. **However it is absolutely needed**. When resolving a path with brackets to a property defined by an addon, you get an `IDProperty` disguised as a `PropertyRNA` which will not have the correct flags set. By checking if a property `is_animatable` in python, all that do not have that can be skipped. Also making sure the path is passed without brackets in the correct cases. Pull Request: https://projects.blender.org/blender/blender/pulls/121520
This commit is contained in:
committed by
Christoph Lendenfeld
parent
fa201712e1
commit
eee32726c7
@@ -246,11 +246,19 @@ def bake_action_iter(
|
||||
if frame is None or not custom_props:
|
||||
return
|
||||
for key, value in custom_props.items():
|
||||
if key in obj.bl_rna.properties and not obj.bl_rna.properties[key].is_animatable:
|
||||
continue
|
||||
obj[key] = value
|
||||
if key in obj.bl_rna.properties:
|
||||
rna_path = key
|
||||
else:
|
||||
rna_path = f'["{bpy.utils.escape_identifier(key)}"]'
|
||||
try:
|
||||
obj.keyframe_insert(f'["{bpy.utils.escape_identifier(key)}"]', frame=frame, group=group_name)
|
||||
obj.keyframe_insert(rna_path, frame=frame, group=group_name)
|
||||
except TypeError:
|
||||
# Non animatable properties (datablocks, etc) cannot be keyed.
|
||||
# The is_animatable check above is per property. A property in isolation
|
||||
# may be considered animatable, but it could be owned by a data-block that
|
||||
# itself cannot be animated.
|
||||
continue
|
||||
|
||||
def pose_frame_info(obj):
|
||||
|
||||
@@ -220,8 +220,13 @@ def RKS_GEN_custom_props(_ksi, _context, ks, data):
|
||||
# ignore special "_RNA_UI" used for UI editing
|
||||
if cprop_name == "_RNA_UI":
|
||||
continue
|
||||
if cprop_name in data.bl_rna.properties and not data.bl_rna.properties[cprop_name].is_animatable:
|
||||
continue
|
||||
|
||||
prop_path = '["{:s}"]'.format(bpy.utils.escape_identifier(cprop_name))
|
||||
if cprop_name in data.bl_rna.properties:
|
||||
prop_path = cprop_name
|
||||
else:
|
||||
prop_path = '["{:s}"]'.format(bpy.utils.escape_identifier(cprop_name))
|
||||
|
||||
try:
|
||||
rna_property = data.path_resolve(prop_path, False)
|
||||
|
||||
@@ -224,13 +224,16 @@ static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static bool is_idproperty_keyable(IDProperty *prop, const PropertyRNA *property_rna)
|
||||
static bool is_idproperty_keyable(IDProperty *id_prop, PointerRNA *ptr, PropertyRNA *prop)
|
||||
{
|
||||
if (RNA_property_is_runtime(property_rna)) {
|
||||
/* While you can cast the IDProperty* to a PropertyRNA* and pass it to the functions, this
|
||||
* does not work because it will not have the right flags set. Instead the resolved
|
||||
* PointerRNA and PropertyRNA need to be passed. */
|
||||
if (!RNA_property_anim_editable(ptr, prop)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ELEM(prop->type,
|
||||
if (ELEM(id_prop->type,
|
||||
eIDPropertyType::IDP_BOOLEAN,
|
||||
eIDPropertyType::IDP_INT,
|
||||
eIDPropertyType::IDP_FLOAT,
|
||||
@@ -239,8 +242,8 @@ static bool is_idproperty_keyable(IDProperty *prop, const PropertyRNA *property_
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prop->type == eIDPropertyType::IDP_ARRAY) {
|
||||
if (ELEM(prop->subtype,
|
||||
if (id_prop->type == eIDPropertyType::IDP_ARRAY) {
|
||||
if (ELEM(id_prop->subtype,
|
||||
eIDPropertyType::IDP_BOOLEAN,
|
||||
eIDPropertyType::IDP_INT,
|
||||
eIDPropertyType::IDP_FLOAT,
|
||||
@@ -305,18 +308,27 @@ static blender::Vector<std::string> construct_rna_paths(PointerRNA *ptr)
|
||||
}
|
||||
if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) {
|
||||
if (properties) {
|
||||
LISTBASE_FOREACH (IDProperty *, prop, &properties->data.group) {
|
||||
char name_escaped[MAX_IDPROP_NAME * 2];
|
||||
BLI_str_escape(name_escaped, prop->name, sizeof(name_escaped));
|
||||
std::string path = fmt::format("[\"{}\"]", name_escaped);
|
||||
LISTBASE_FOREACH (IDProperty *, id_prop, &properties->data.group) {
|
||||
PointerRNA resolved_ptr;
|
||||
PropertyRNA *resolved_prop;
|
||||
const bool is_resolved = RNA_path_resolve_property(
|
||||
std::string path = id_prop->name;
|
||||
/* Resolving the path twice, once as RNA property (without brackets, "propname"), and once
|
||||
* as ID property (with brackets, '["propname"]'). This is required to support IDProperties
|
||||
* that have been defined as part of an addon. Those need to be animated through an RNA
|
||||
* path without the brackets. */
|
||||
bool is_resolved = RNA_path_resolve_property(
|
||||
ptr, path.c_str(), &resolved_ptr, &resolved_prop);
|
||||
if (!is_resolved) {
|
||||
char name_escaped[MAX_IDPROP_NAME * 2];
|
||||
BLI_str_escape(name_escaped, id_prop->name, sizeof(name_escaped));
|
||||
path = fmt::format("[\"{}\"]", name_escaped);
|
||||
is_resolved = RNA_path_resolve_property(
|
||||
ptr, path.c_str(), &resolved_ptr, &resolved_prop);
|
||||
}
|
||||
if (!is_resolved) {
|
||||
continue;
|
||||
}
|
||||
if (is_idproperty_keyable(prop, resolved_prop)) {
|
||||
if (is_idproperty_keyable(id_prop, &resolved_ptr, resolved_prop)) {
|
||||
paths.append(path);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user