Fix T91393: Duplicating an action with python crashes Blender.

Own mistake when making NLA overridable, instead of assuming things
about the ID owner of the animation data being processed, properly
return and use the one found by `ED_actedit_animdata_from_context`.
This commit is contained in:
Bastien Montagne 2021-09-28 17:37:35 +02:00
parent 53fa4801a0
commit 330a04d7c7
2 changed files with 31 additions and 22 deletions

View File

@ -861,7 +861,7 @@ void ED_operatormacros_action(void);
/* XXX: Should we be doing these here, or at all? */
/* Action Editor - Action Management */
struct AnimData *ED_actedit_animdata_from_context(struct bContext *C);
struct AnimData *ED_actedit_animdata_from_context(struct bContext *C, struct ID **r_adt_id_owner);
void ED_animedit_unlink_action(struct bContext *C,
struct ID *id,
struct AnimData *adt,

View File

@ -71,7 +71,7 @@
/* ACTION CREATION */
/* Helper function to find the active AnimData block from the Action Editor context */
AnimData *ED_actedit_animdata_from_context(bContext *C)
AnimData *ED_actedit_animdata_from_context(bContext *C, ID **r_adt_id_owner)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
Object *ob = CTX_data_active_object(C);
@ -82,12 +82,18 @@ AnimData *ED_actedit_animdata_from_context(bContext *C)
/* Currently, "Action Editor" means object-level only... */
if (ob) {
adt = ob->adt;
if (r_adt_id_owner) {
*r_adt_id_owner = &ob->id;
}
}
}
else if (saction->mode == SACTCONT_SHAPEKEY) {
Key *key = BKE_key_from_object(ob);
if (key) {
adt = key->adt;
if (r_adt_id_owner) {
*r_adt_id_owner = &key->id;
}
}
}
@ -212,6 +218,7 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
bAction *oldact = NULL;
AnimData *adt = NULL;
ID *adt_id_owner = NULL;
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
@ -225,13 +232,14 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
/* stash the old action to prevent it from being lost */
if (ptr.type == &RNA_AnimData) {
adt = ptr.data;
adt_id_owner = ptr.owner_id;
}
else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
adt = ED_actedit_animdata_from_context(C);
adt = ED_actedit_animdata_from_context(C, &adt_id_owner);
}
}
else {
adt = ED_actedit_animdata_from_context(C);
adt = ED_actedit_animdata_from_context(C, &adt_id_owner);
oldact = adt->action;
}
{
@ -239,8 +247,9 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
/* Perform stashing operation - But only if there is an action */
if (adt && oldact) {
BLI_assert(adt_id_owner != NULL);
/* stash the action */
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr.owner_id))) {
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(adt_id_owner))) {
/* The stash operation will remove the user already
* (and unlink the action from the AnimData action slot).
* Hence, we must unset the ref to the action in the
@ -306,7 +315,7 @@ static bool action_pushdown_poll(bContext *C)
{
if (ED_operator_action_active(C)) {
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
/* Check for AnimData, Actions, and that tweak-mode is off. */
if (adt && saction->action) {
@ -326,7 +335,8 @@ static bool action_pushdown_poll(bContext *C)
static int action_pushdown_exec(bContext *C, wmOperator *op)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
ID *adt_id_owner = NULL;
AnimData *adt = ED_actedit_animdata_from_context(C, &adt_id_owner);
/* Do the deed... */
if (adt) {
@ -339,8 +349,7 @@ static int action_pushdown_exec(bContext *C, wmOperator *op)
}
/* action can be safely added */
const Object *ob = CTX_data_active_object(C);
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ob));
BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(adt_id_owner));
/* Stop displaying this action in this editor
* NOTE: The editor itself doesn't set a user...
@ -373,7 +382,8 @@ void ACTION_OT_push_down(wmOperatorType *ot)
static int action_stash_exec(bContext *C, wmOperator *op)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
ID *adt_id_owner = NULL;
AnimData *adt = ED_actedit_animdata_from_context(C, &adt_id_owner);
/* Perform stashing operation */
if (adt) {
@ -385,8 +395,7 @@ static int action_stash_exec(bContext *C, wmOperator *op)
}
/* stash the action */
Object *ob = CTX_data_active_object(C);
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) {
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(adt_id_owner))) {
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
* the user-count fixes. Hence, we must unset this ref
@ -439,7 +448,7 @@ void ACTION_OT_stash(wmOperatorType *ot)
static bool action_stash_create_poll(bContext *C)
{
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
/* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
/* NOTE: unlike for pushdown,
@ -471,7 +480,8 @@ static bool action_stash_create_poll(bContext *C)
static int action_stash_create_exec(bContext *C, wmOperator *op)
{
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
ID *adt_id_owner = NULL;
AnimData *adt = ED_actedit_animdata_from_context(C, &adt_id_owner);
/* Check for no action... */
if (saction->action == NULL) {
@ -488,8 +498,7 @@ static int action_stash_create_exec(bContext *C, wmOperator *op)
}
/* stash the action */
Object *ob = CTX_data_active_object(C);
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) {
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(adt_id_owner))) {
bAction *new_action = NULL;
/* Create new action not based on the old one
@ -636,7 +645,7 @@ static bool action_unlink_poll(bContext *C)
{
if (ED_operator_action_active(C)) {
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
/* Only when there's an active action, in the right modes... */
if (saction->action && adt) {
@ -650,7 +659,7 @@ static bool action_unlink_poll(bContext *C)
static int action_unlink_exec(bContext *C, wmOperator *op)
{
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
if (adt && adt->action) {
@ -775,7 +784,7 @@ static bool action_layer_next_poll(bContext *C)
{
/* Action Editor's action editing modes only */
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
if (adt) {
/* only allow if we're in tweak-mode, and there's something above us... */
if (adt->flag & ADT_NLA_EDIT_ON) {
@ -809,7 +818,7 @@ static bool action_layer_next_poll(bContext *C)
static int action_layer_next_exec(bContext *C, wmOperator *op)
{
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
NlaTrack *act_track;
Scene *scene = CTX_data_scene(C);
@ -886,7 +895,7 @@ static bool action_layer_prev_poll(bContext *C)
{
/* Action Editor's action editing modes only */
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
if (adt) {
if (adt->flag & ADT_NLA_EDIT_ON) {
/* Tweak Mode: We need to check if there are any tracks below the active one
@ -920,7 +929,7 @@ static bool action_layer_prev_poll(bContext *C)
static int action_layer_prev_exec(bContext *C, wmOperator *op)
{
AnimData *adt = ED_actedit_animdata_from_context(C);
AnimData *adt = ED_actedit_animdata_from_context(C, NULL);
NlaTrack *act_track;
NlaTrack *nlt;