2
$\begingroup$

I want to save a dict of random information to the scene, per .blend file, the dict updates fine but on reload it is back to its defaults.

    bl_info = {
    "name": "Test",
    "author": "Test",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "description": "",
    "category": "3D View"}

import bpy
from bpy.app.handlers import persistent

region_3d_settings = (
            "view_location",
            "view_distance",
            "view_rotation",
            "view_perspective"
        )

class Test_Variables(bpy.types.PropertyGroup):

    startup_settings = {"clip" : {"start" : 0.01, "end" : 100},
                          "viewport" : {},
                          }

@persistent
def pre_save(scene):

    self_vars = bpy.context.scene.test_vars

    for a in bpy.context.screen.areas:
        if a.type == 'VIEW_3D':

            for setting in region_3d_settings:
                self_vars.startup_settings["viewport"][setting] = getattr(a.spaces[0].region_3d, setting)

            for s in a.spaces:
                if s.type == 'VIEW_3D':
                    self_vars.startup_settings["clip"]["start"] = s.clip_start
                    self_vars.startup_settings["clip"]["end"] = s.clip_end
                    break


classes = (
    Test_Variables,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.test_vars = bpy.props.PointerProperty(type = Test_Variables)

    bpy.app.handlers.save_pre.append(pre_save)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.test_vars

    if pre_save.__name__ in [hand.__name__ for hand in bpy.app.handlers.save_pre]:
        bpy.app.handlers.save_pre.remove(pre_save)

if __name__ == "__main__":
    register()
$\endgroup$
1

1 Answer 1

5
$\begingroup$

Make them properties

In as much as you can define anything to a property group, only those that are defined as bpy.props properties, or wired up as @property with setter, will be saved to blender file (or elsewhere).

In example above, to use bpy.props and have them saved to blender clip would be a pointer property, and start a float property of another propertygroup. Can create a property group with type,

clip_class = type("Clip", (PropertyGroup,), 
        {"start" : FloatProperty(),
        }
    )

See the bpy.props documentation, in particular the setter getter example which emulates how a property is saved on the blend as an ID property on the object.

Better still

Alternatively, to save a "junk" dictionary with only string, integer, bool and float values use the rna

As used here

https://blender.stackexchange.com/a/54040/15543

can define a custom property on a scene and set arbitrary values in the dictionary that stores values to decorate the UI. If you add a custom property named "prop" using the UI. All the details filled in via the popup are saved, and used to decorate the display of the prop in the UI. Recommend viewing the source of rna_prop_ui.py

We can abuse this system.

 C.scene['_RNA_UI']['prop']
<bpy id prop: owner="SCScene", name="prop", address=0x7facac90e108>

>>> C.scene['_RNA_UI']['prop'].to_dict()
{'min': 0.0, 'soft_min': 0.0, 'max': 1.0, 'soft_max': 1.0, 'default': 1.0}

Can set, save file

>>> foobar = {"foo":True, "bar":100}
>>> C.scene['_RNA_UI']['prop']['foobar'] = foobar

and reopen, dictionary remains. The boolean is converted to int.

>>> C.scene['_RNA_UI']['prop'].to_dict()
{'min': 0.0, 'soft_min': 0.0, 'max': 1.0, 'soft_max': 1.0, 'default': 1.0, 'foobar': {'foo': 1, 'bar': 100}}

Another option is to use json to convert / read string dictionaries and store the dictionary as a string.

In your persistent handler, (add code to handle key errors)

self_vars = scene['_RNA_UI']['prop']['foobar']

notice scene is passed to the handler.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .