Undo breaks my addon

Hello all! First-timer here :wink:

I am writing addon, that adds keyframes to a group of objects at a time.

In example .blend file I created two objects: Group_obj1 and Group_obj2.

If you select both of them and go to View3D > Sidebar > View Tab > Group Poses you can add keyframes to both of them when you hit Add Keypose button, both object will get keyframes by location at frame 1.

What I do next to break addon:

  1. Go to frame 100. Hit button Add Keypose
  2. Go to frame 150 and change Y location of one of the objects. Hit Add Keypose
  3. Press Ctrl+Z so keyframes in frame 150 are not set.
  4. Hit Add Keypose again and I get an error:
Traceback (most recent call last):

  File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\addons\out_exmpl\__init__.py", line 98, in execute
    GroupObjectsData.add_keypose(current_frame)
  File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\addons\out_exmpl\__init__.py", line 27, in add_keypose
    x, y, z = obj.location
ReferenceError: StructRNA of type Object has been removed

How can I handle this Undo, so nothing breaks?

I want to keep all backend associated with inserting keyframes and other animation stuff in my own class GroupObjects, which is not inherrited from bpy.

My __init__.py: https://gist.github.com/spawly/3ceee6897519e74c3d3cddd3f96ef073

My .blend file with all objects added: https://drive.google.com/file/d/1KlRZgFnQbrlKr349BMgAlxDyQM0--d8x/view?usp=sharing

Any help is very-very appreciated. My first time writing aby addon for blender :slightly_smiling_face:

In general you simply can’t keep references to Blender objects in a global variable like this. Even without undo, those objects may be deleted and the references may become invalid.

If you want to keep references, you have to either use a PointerProperty and store them on a Blender data structure somewhere, or only store them for the lifetime of an operator.

3 Likes

Hi! Thanks for the good input!

I thought I could use references, since I don’t do shallow or deep copy of the objects. However, it seems not the case (

I need to store objects in some class permanently and do not like the idea to store them for the operator lifetime.

Do you have and idea where is it better to store Pointer? In scene? What is the best practice for that?
If you came across any good examples of using PointerProperty, I would be really greatful :blush:

The scene may be a good place, or maybe there is no need to keep a list, and rather some data should be attached to objects. It all depends on the use case.

It’s often tempting to store all your data together in a way that’s most convenient for UI drawing or operators. But that also tends to not work well with object delete, duplicate, append, undo, etc.

I usually store the data as some kind of key, usually the name, and look it up when I need it. But it’s also kind of bad practice to write an addon where this becomes an issue. If you re-write your addon as a modal operator, maybe you can avoid the problem to begin with.

I solved this problem by using another type of referencing objects: I store list of object names instead of references.