2
$\begingroup$

I'm trying to write script that will automatically reload file every few seconds. In order to do that I wrote following plugin:

bl_info = {"name": "[PonyKart] Auto scene update", "category": "Scene"}

import bpy
import threading

DELAY=30
timer=None

def reloader():
    print("Updating")
    bpy.ops.wm.save_reload()

def register():
    print("Timer registered")
    timer=threading.Timer(DELAY,reloader)
    timer.start()

def unregister():
    print("Timer cancelled")
    timer.cancel()

But while it indeed does save file properly, it crashes Blender after doing so (I so i think it crashes when Blender opens file)

Just for reference here is code responsible for save_reload from amaranth plugin:

"""Save and Reload the current blend file"""
bl_idname = "wm.save_reload"
bl_label = "Save & Reload"

def save_reload(self, context, path):
    if not path:
        bpy.ops.wm.save_as_mainfile("INVOKE_AREA")
        return
    bpy.ops.wm.save_mainfile()
    self.report({"INFO"}, "Saved & Reloaded")
    bpy.ops.wm.open_mainfile("EXEC_DEFAULT", filepath=path)

def execute(self, context):
    path = bpy.data.filepath
    self.save_reload(context, path)
    return {"FINISHED"}

I'm trying to allow online collaboration on single file. When person A works on file a.blend and person B on file b.blend and they cross-link each others grouped objects (lets say personA_group and personB_group) then with periodic file reaload users can get updated info on scene. Maybe it's not super realtime, but it works and uses relatively stable Blender mechanics.

I know there's verse and I know it doesn't work. Apart from spending like days trying to set it up after I managed to do it it crashes every few minutes and glitches as hell. It's so extremely unstable on hi-poly meshes that it's unusable. Also requires high bandwidth while method above (if we enable Blender file compression) requires only sending few MB file (usually around 1-2) over network every lets say 60 sec. It's possible to implement such mechanics using samba share. According to initial tests file reload over our samba share takes around 3-4 seconds using awfully slow connection so it's usable.

$\endgroup$
2
  • $\begingroup$ hard to tell what's going wrong, possibly delay is too short, try if this happens with large delay. but could you add some information on why you do it?? $\endgroup$
    – Noidea
    Commented Oct 7, 2016 at 16:32
  • $\begingroup$ updated. 30 secons is quite big interval also I tried just manually creating thread from Blender console and the same happens - it crashes. Several methods behave weird when launched in separate thread - .quit_blender() also doesn't work. I tried to import bpy inside this callback method but it doesn't help either $\endgroup$
    – Lapsio
    Commented Oct 7, 2016 at 17:08

1 Answer 1

2
$\begingroup$

Quote from the api documentation

Python threading with Blender only works properly when the threads finish up before the script does


There are two ways i know of to periodically run python code:

Register a handler for scene_update_post:

import bpy
import time

t = [0.0] * 3
t[0] = time.time()
handles = bpy.app.handlers.scene_update_post

@persistent
def on_scene_update(scene):
    t[1] = time.time()
    t[2]+= t[1] - t[0]
    t[0] = t[1]
    print("Time elapsed %f" % t[2])

    if t[2] > 20.0:
        handles.remove(on_scene_update)

handles.append(on_scene_update) 

Use a modal operator (in this case the code only runs when the user interacts with blender):

import bpy
import time

class OT_INFO_time_elapsed(bpy.types.Operator):
    bl_idname = "info.time_elapsed"
    bl_label = "Print elapsed time to the console"
    bl_options = set()

    def invoke(self, context, event):
        self.current = time.time()
        self.prev = self.current
        self.elapsed = 0.0
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def modal(self, context, event):
        self.current = time.time()
        self.elapsed += self.current - self.prev
        self.prev = self.current
        print("Time elapsed: %f" % self.elapsed)            
        return {'PASS_THROUGH'}

def register():
    bpy.utils.register_class(OT_INFO_time_elapsed)

def unregister():
    bpy.utils.unregister_class(OT_INFO_time_elapsed)

if __name__ == "__main__":
    register()

Since you intend to reload the file only the handler using the @persistent decorator will work.

$\endgroup$
3
  • $\begingroup$ so if i'd like to use first variant - I should put save_reload() after handles.remove(...) right? then it'll reload file after user updates scene AND required time elapsed? $\endgroup$
    – Lapsio
    Commented Oct 7, 2016 at 18:13
  • 1
    $\begingroup$ I'm getting persistent is not defined $\endgroup$
    – Lapsio
    Commented Oct 7, 2016 at 18:15
  • 2
    $\begingroup$ after importing @persistent this first variant also crashes blender. Exactly in the same way as thread. But modal operator does not and works properly so I think I have to use this method. $\endgroup$
    – Lapsio
    Commented Oct 7, 2016 at 18:28

You must log in to answer this question.

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