Merge pull request #2238 from MoritzBrueckner/background-mode
Fix threading and publishing in background mode
This commit is contained in:
commit
20540ccb11
|
@ -1,5 +1,6 @@
|
|||
import importlib
|
||||
import os
|
||||
import queue
|
||||
import sys
|
||||
|
||||
import bpy
|
||||
|
@ -89,19 +90,38 @@ def send_operator(op):
|
|||
else: # Rebuild
|
||||
make.patch()
|
||||
|
||||
def always():
|
||||
|
||||
def always() -> float:
|
||||
# Force ui redraw
|
||||
if state.redraw_ui and context_screen != None:
|
||||
if state.redraw_ui and context_screen is not None:
|
||||
for area in context_screen.areas:
|
||||
if area.type == 'VIEW_3D' or area.type == 'PROPERTIES':
|
||||
area.tag_redraw()
|
||||
state.redraw_ui = False
|
||||
# TODO: depsgraph.updates only triggers material trees
|
||||
space = arm.utils.logic_editor_space(context_screen)
|
||||
if space != None:
|
||||
if space is not None:
|
||||
space.node_tree.arm_cached = False
|
||||
return 0.5
|
||||
|
||||
|
||||
def poll_threads() -> float:
|
||||
"""Polls the thread callback queue and if a thread has finished, it
|
||||
is joined with the main thread and the corresponding callback is
|
||||
executed in the main thread.
|
||||
"""
|
||||
try:
|
||||
thread, callback = make.thread_callback_queue.get(block=False)
|
||||
except queue.Empty:
|
||||
return 0.25
|
||||
|
||||
thread.join()
|
||||
callback()
|
||||
|
||||
# Quickly check if another thread has finished
|
||||
return 0.01
|
||||
|
||||
|
||||
appended_py_paths = []
|
||||
context_screen = None
|
||||
|
||||
|
@ -181,7 +201,9 @@ def register():
|
|||
bpy.app.handlers.load_post.append(on_load_post)
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update_post)
|
||||
# bpy.app.handlers.undo_post.append(on_undo_post)
|
||||
|
||||
bpy.app.timers.register(always, persistent=True)
|
||||
bpy.app.timers.register(poll_threads, persistent=True)
|
||||
|
||||
if arm.utils.get_fp() != '':
|
||||
appended_py_paths = []
|
||||
|
@ -198,6 +220,9 @@ def register():
|
|||
|
||||
|
||||
def unregister():
|
||||
bpy.app.timers.unregister(poll_threads)
|
||||
bpy.app.timers.unregister(always)
|
||||
|
||||
bpy.app.handlers.load_post.remove(on_load_post)
|
||||
bpy.app.handlers.depsgraph_update_post.remove(on_depsgraph_update_post)
|
||||
# bpy.app.handlers.undo_post.remove(on_undo_post)
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import errno
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
from queue import Queue
|
||||
import shlex
|
||||
import shutil
|
||||
import time
|
||||
import stat
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from typing import Callable
|
||||
import webbrowser
|
||||
import shlex
|
||||
import errno
|
||||
import math
|
||||
|
||||
import bpy
|
||||
|
||||
|
@ -28,15 +29,42 @@ import arm.write_data as write_data
|
|||
scripts_mtime = 0 # Monitor source changes
|
||||
profile_time = 0
|
||||
|
||||
def run_proc(cmd, done):
|
||||
def fn(p, done):
|
||||
p.wait()
|
||||
if done != None:
|
||||
# Queue of threads and their done callbacks. Item format: [thread, done]
|
||||
thread_callback_queue = Queue(maxsize=0)
|
||||
|
||||
|
||||
def run_proc(cmd, done: Callable) -> subprocess.Popen:
|
||||
"""Creates a subprocess with the given command and returns it.
|
||||
|
||||
If Blender is not running in background mode, a thread is spawned
|
||||
that waits until the subprocess has finished executing to not freeze
|
||||
the UI, otherwise (in background mode) execution is blocked until
|
||||
the subprocess has finished.
|
||||
|
||||
If `done` is not `None`, it is called afterwards in the main thread.
|
||||
"""
|
||||
use_thread = not bpy.app.background
|
||||
|
||||
def wait_for_proc(proc: subprocess.Popen):
|
||||
proc.wait()
|
||||
|
||||
if use_thread:
|
||||
# Put the done callback into the callback queue so that it
|
||||
# can be received by a polling function in the main thread
|
||||
thread_callback_queue.put([threading.current_thread(), done], block=True)
|
||||
else:
|
||||
done()
|
||||
|
||||
p = subprocess.Popen(cmd)
|
||||
threading.Thread(target=fn, args=(p, done)).start()
|
||||
|
||||
if use_thread:
|
||||
threading.Thread(target=wait_for_proc, args=(p,)).start()
|
||||
else:
|
||||
wait_for_proc(p)
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def compile_shader_pass(res, raw_shaders_path, shader_name, defs, make_variants):
|
||||
os.chdir(raw_shaders_path + '/' + shader_name)
|
||||
|
||||
|
|
|
@ -626,7 +626,6 @@ class ARM_PT_ArmoryExporterPanel(bpy.types.Panel):
|
|||
row = layout.row(align=True)
|
||||
row.alignment = 'EXPAND'
|
||||
row.scale_y = 1.3
|
||||
row.enabled = wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0
|
||||
row.operator("arm.build_project", icon="MOD_BUILD")
|
||||
# row.operator("arm.patch_project")
|
||||
row.operator("arm.publish_project", icon="EXPORT")
|
||||
|
@ -1053,10 +1052,15 @@ class ArmoryStopButton(bpy.types.Operator):
|
|||
return{'FINISHED'}
|
||||
|
||||
class ArmoryBuildProjectButton(bpy.types.Operator):
|
||||
'''Build and compile project'''
|
||||
"""Build and compile project"""
|
||||
bl_idname = 'arm.build_project'
|
||||
bl_label = 'Build'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
return wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0
|
||||
|
||||
def execute(self, context):
|
||||
# Compare version Blender and Armory (major, minor)
|
||||
if not arm.utils.compare_version_blender_arm():
|
||||
|
@ -1093,10 +1097,15 @@ class ArmoryBuildProjectButton(bpy.types.Operator):
|
|||
return{'FINISHED'}
|
||||
|
||||
class ArmoryPublishProjectButton(bpy.types.Operator):
|
||||
'''Build project ready for publishing'''
|
||||
"""Build project ready for publishing."""
|
||||
bl_idname = 'arm.publish_project'
|
||||
bl_label = 'Publish'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
return wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0
|
||||
|
||||
def execute(self, context):
|
||||
# Compare version Blender and Armory (major, minor)
|
||||
if not arm.utils.compare_version_blender_arm():
|
||||
|
|
Loading…
Reference in a new issue