1
$\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$
  • $\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 Oct 7 '16 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 Oct 7 '16 at 17:08
1
$\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$
  • $\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 Oct 7 '16 at 18:13
  • 1
    $\begingroup$ I'm getting persistent is not defined $\endgroup$ – Lapsio Oct 7 '16 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 Oct 7 '16 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.