Can I perform an action when a file is saved or loaded?

If I create a Blender file with a single plane that has 10 000 particles of hair, the resulting file size is 9.9 MB.

If, before saving, I reduce the "Number" (RNA ParticleSettings.count) to 1, the resulting file size is only 435 KB.

Because the hair is randomly generated with a specified seed (ParticleSystem.seed), I can open the 435 KB-file and set the number back to 10 000 and get the exact same hair system generated.

In scenes where I have a lot of hair (especially grass, which can require millions of particles), I've seen differences as high as 50 MB. Taking into account the two backup files, that's 150 MB of disk (and, for me, cloud) space saved, which is a clear advantage. The downsides of this method, however, include:

• It's cumbersome. I don't want to have to remember to disable something before saving and re-enable it when I load.
• It's error-prone. I find myself adding README.txt files to my directories indicating the desired number of particles for each object, because otherwise I forget and my renders are inconsistent (all of a sudden the grass doubles).
• It's forgettable. I've lost days of render time due to rendering a scene with a single grass particle because I've forgotten to reset the number. Obviously this is a human error problem, but it's not helped by Blender.

Is there a way I can attach a "save hook" and "open hook" to a file to do this automatically for me? I could easily write a Python script with custom settings for each particle system:

import bpy

def hair_reduce():
for ps in bpy.data.particles:
if ps.type == 'HAIR' and not 'actual_hair_count' in ps:
ps['actual_hair_count'] = ps.count
ps.count = 1

def hair_apply():
for ps in bpy.data.particles:
if ps.type == 'HAIR' and 'actual_hair_count' in ps:
ps.count = int(ps['actual_hair_count'])
del ps['actual_hair_count']


The trick, however, is to have these functions called when the file is saved or loaded.

Can I attach a save/load hook to Blender, or otherwise perform an action when the file is saved or loaded?

• Sounds like a bug, should probably be reported on the tracker. – Aldrik Jun 9 '13 at 22:19

We can register handlers that will be executed before, or after, specific operations. The handler lists are all in bpy.app.handlers, and looking at your requirement, the handler list to use is save_pre (executed before saving) and load_post (executed after loading).

The function needs to be persistent, so they won't disappear every time a new file is loaded. Here's an example of how to register it, edited from my own addon needing such feature:

import bpy
from bpy.app.handlers import persistent

@persistent
def hair_reduce(dummy):
print('hair_reduce')

@persistent
def hair_apply(dummy):
print('hair_apply')

def register():
if not hair_reduce in bpy.app.handlers.save_pre:
bpy.app.handlers.save_pre.append(hair_reduce)

def unregister():
if hair_reduce in bpy.app.handlers.save_pre:
bpy.app.handlers.save_pre.remove(hair_reduce)

• Thanks for your answer. What does the dummy parameter do? Also, shouldn't it be save_pre.append(hair_reduce)? – wchargin Jun 9 '13 at 21:35
• Also, can I add hair_apply to save_post as well? – wchargin Jun 9 '13 at 21:45
• Whoops, forgot to replace that one. In several handler lists I've used, the argument's value is always None. So I simply name it the way the example code do. – Adhi Jun 9 '13 at 22:05
• What, so the hair settings are applied back after saving? I think you can. This is edited from my addon saving and restoring some other settings, originally using both save_pre and save_post, and they worked. – Adhi Jun 9 '13 at 22:08
• Okay, thanks. One more thing: could you please advise me as to why I can't enable my addon after installing it from file? The code is here. – wchargin Jun 9 '13 at 22:10