Fix #119615: Anim, Crash with NLA tweak mode and linked Armatures #119632

Merged
5 changed files with 112 additions and 1 deletions
Showing only changes of commit cf0a5d1581 - Show all commits

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 22
#define BLENDER_FILE_SUBVERSION 23
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -395,6 +395,12 @@ struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
* Make the given NLA-Strip the active one within the given block.
*/
void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip);
/**
* Find the NLA-strip with the given name within the given track.
*

Might be worth mentioning what happens if no strip is found given the name.

Might be worth mentioning what happens if no strip is found given the name.
* \return pointer to the strip, or nullptr when not found.
*/
struct NlaStrip *BKE_nlastrip_find_by_name(struct NlaTrack *nlt, const char *name);
/**
* Does the given NLA-strip fall within the given bounds (times)?.

View File

@ -1457,6 +1457,31 @@ void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
}
}
static NlaStrip *nlastrip_find_by_name(ListBase /* NlaStrip */ *strips, const char *name)
{
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
if (STREQ(strip->name, name)) {
return strip;
}
if (strip->type != NLASTRIP_TYPE_META) {
continue;
}
NlaStrip *inner_strip = nlastrip_find_by_name(&strip->strips, name);
if (inner_strip != nullptr) {
return inner_strip;
}
}
return nullptr;
}
NlaStrip *BKE_nlastrip_find_by_name(NlaTrack *nlt, const char *name)
{
return nlastrip_find_by_name(&nlt->strips, name);
}
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
{
const float stripLen = (strip) ? strip->end - strip->start : 0.0f;

View File

@ -16,6 +16,7 @@
/* Define macros in `DNA_genfile.h`. */
#define DNA_GENFILE_VERSIONING_MACROS
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
@ -57,6 +58,7 @@
#include "BKE_main.hh"
#include "BKE_material.h"
#include "BKE_mesh_legacy_convert.hh"
#include "BKE_nla.h"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BKE_scene.h"
@ -356,6 +358,51 @@ static void versioning_replace_splitviewer(bNodeTree *ntree)
}
}
/**
* Exit NLA tweakmode when the AnimData struct has insufficient information.
*
* When NLA tweakmode is enabled, Blender expects certain pointers to be set up
* correctly, and if that fails, can crash. This function ensures that
* everything is consistent, by exiting tweakmode everywhere there's missing
* pointers.
*
* This shouldn't happen, but the example blend file attached to #119615 needs
* this.
*/
static void version_nla_tweakmode_incomplete(Main *bmain)
{
bool any_valid_tweakmode_left = false;
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
AnimData *adt = BKE_animdata_from_id(id);
if (!adt || !(adt->flag & ADT_NLA_EDIT_ON)) {
continue;
}
if (adt->act_track && adt->actstrip) {
/* Expected case. */
any_valid_tweakmode_left = true;
continue;
}
/* Not enough info in the blend file to reliably stay in tweak mode. This is the most important
* part of this versioning code, as it prevents future nullptr access. */
BKE_nla_tweakmode_exit(adt);
}
FOREACH_MAIN_ID_END;
if (any_valid_tweakmode_left) {
/* There are still NLA strips correctly in tweak mode. */
return;
}
/* Nothing is in a valid tweakmode, so just disable the corresponding flags on all scenes. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->flag &= ~SCE_NLA_EDIT_ON;
}
}
void do_versions_after_linking_400(FileData *fd, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 9)) {
@ -450,6 +497,10 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 23)) {
version_nla_tweakmode_incomplete(bmain);
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@ -12,6 +12,7 @@
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@ -189,6 +190,34 @@ bool rna_AnimData_tweakmode_override_apply(Main * /*bmain*/,
anim_data_dst->flag = (anim_data_dst->flag & ~ADT_NLA_EDIT_ON) |
(anim_data_src->flag & ADT_NLA_EDIT_ON);
if (!(anim_data_dst->flag & ADT_NLA_EDIT_ON)) {
/* If tweak mode is not enabled, there's nothing left to do. */
return true;
}
if (!anim_data_src->act_track || !anim_data_src->actstrip) {
/* If there is not enough information to find the active track/strip, don't bother. */
return true;
}
/* AnimData::act_track and AnimData::actstrip are not directly exposed to RNA as editable &
* overridable, so the override doesn't contain this info. Reconstruct the pointers by name. */
for (NlaTrack *track : blender::ListBaseWrapper<NlaTrack>(anim_data_dst->nla_tracks)) {
if (!STREQ(track->name, anim_data_src->act_track->name)) {
continue;
}
NlaStrip *strip = BKE_nlastrip_find_by_name(track, anim_data_src->actstrip->name);
if (!strip) {
continue;
}
anim_data_dst->act_track = track;
anim_data_dst->actstrip = strip;
break;
}
return true;
}