Merge branch 'feature/event_driven_updates' into develop
This commit is contained in:
commit
b3230177d8
@ -8,5 +8,8 @@ build:
|
||||
name: multi_user
|
||||
paths:
|
||||
- multi_user
|
||||
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- develop
|
||||
|
||||
|
@ -11,4 +11,7 @@ test:
|
||||
- python -m pip install blender-addon-tester
|
||||
- python scripts/test_addon.py
|
||||
|
||||
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- develop
|
||||
|
@ -44,7 +44,7 @@ from . import environment, utils
|
||||
|
||||
|
||||
DEPENDENCIES = {
|
||||
("replication", '0.0.21a4'),
|
||||
("replication", '0.0.21a5'),
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,20 +85,22 @@ class ApplyTimer(Timer):
|
||||
super().__init__(timout)
|
||||
|
||||
def execute(self):
|
||||
client = operators.client
|
||||
if client and client.state['STATE'] == STATE_ACTIVE:
|
||||
nodes = client.list(filter=self._type)
|
||||
client = operators.client
|
||||
if client and client.state['STATE'] == STATE_ACTIVE:
|
||||
if self._type:
|
||||
nodes = client.list(filter=self._type)
|
||||
else:
|
||||
nodes = client.list()
|
||||
|
||||
for node in nodes:
|
||||
node_ref = client.get(uuid=node)
|
||||
|
||||
if node_ref.state == FETCHED:
|
||||
try:
|
||||
client.apply(node)
|
||||
client.apply(node, force=True)
|
||||
except Exception as e:
|
||||
logging.error(f"Fail to apply {node_ref.uuid}: {e}")
|
||||
|
||||
|
||||
class DynamicRightSelectTimer(Timer):
|
||||
def __init__(self, timout=.1):
|
||||
super().__init__(timout)
|
||||
@ -239,7 +241,7 @@ class DrawClient(Draw):
|
||||
|
||||
|
||||
class ClientUpdate(Timer):
|
||||
def __init__(self, timout=.032):
|
||||
def __init__(self, timout=.1):
|
||||
super().__init__(timout)
|
||||
self.handle_quit = False
|
||||
self.users_metadata = {}
|
||||
|
@ -35,7 +35,7 @@ from bpy.app.handlers import persistent
|
||||
from . import bl_types, delayable, environment, presence, ui, utils
|
||||
from replication.constants import (FETCHED, STATE_ACTIVE,
|
||||
STATE_INITIAL,
|
||||
STATE_SYNCING)
|
||||
STATE_SYNCING, RP_COMMON, UP)
|
||||
from replication.data import ReplicatedDataFactory
|
||||
from replication.exception import NonAuthorizedOperationError
|
||||
from replication.interface import Session
|
||||
@ -67,7 +67,7 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
runtime_settings = context.window_manager.session
|
||||
users = bpy.data.window_managers['WinMan'].online_users
|
||||
admin_pass = runtime_settings.password
|
||||
|
||||
use_extern_update = settings.update_method == 'DEPSGRAPH'
|
||||
users.clear()
|
||||
delayables.clear()
|
||||
|
||||
@ -88,18 +88,23 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
bpy_factory.register_type(
|
||||
type_module_class.bl_class,
|
||||
type_module_class,
|
||||
timer=type_local_config.bl_delay_refresh,
|
||||
timer=type_local_config.bl_delay_refresh*1000,
|
||||
automatic=type_local_config.auto_push)
|
||||
|
||||
if type_local_config.bl_delay_apply > 0:
|
||||
delayables.append(
|
||||
delayable.ApplyTimer(
|
||||
timout=type_local_config.bl_delay_apply,
|
||||
target_type=type_module_class))
|
||||
if settings.update_method == 'DEFAULT':
|
||||
if type_local_config.bl_delay_apply > 0:
|
||||
delayables.append(
|
||||
delayable.ApplyTimer(
|
||||
timout=type_local_config.bl_delay_apply,
|
||||
target_type=type_module_class))
|
||||
|
||||
client = Session(
|
||||
factory=bpy_factory,
|
||||
python_path=bpy.app.binary_path_python)
|
||||
python_path=bpy.app.binary_path_python,
|
||||
external_update_handling=use_extern_update)
|
||||
|
||||
if settings.update_method == 'DEPSGRAPH':
|
||||
delayables.append(delayable.ApplyTimer(settings.depsgraph_update_rate/1000))
|
||||
|
||||
# Host a session
|
||||
if self.host:
|
||||
@ -145,7 +150,6 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
logging.error(str(e))
|
||||
|
||||
# Background client updates service
|
||||
#TODO: Refactoring
|
||||
delayables.append(delayable.ClientUpdate())
|
||||
delayables.append(delayable.DrawClient())
|
||||
delayables.append(delayable.DynamicRightSelectTimer())
|
||||
@ -161,6 +165,8 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
|
||||
@client.register('on_connection')
|
||||
def initialize_session():
|
||||
settings = utils.get_preferences()
|
||||
|
||||
for node in client._graph.list_ordered():
|
||||
node_ref = client.get(node)
|
||||
if node_ref.state == FETCHED:
|
||||
@ -180,9 +186,13 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
for d in delayables:
|
||||
d.register()
|
||||
|
||||
if settings.update_method == 'DEPSGRAPH':
|
||||
bpy.app.handlers.depsgraph_update_post.append(depsgraph_evaluation)
|
||||
|
||||
@client.register('on_exit')
|
||||
def desinitialize_session():
|
||||
global delayables, stop_modal_executor
|
||||
settings = utils.get_preferences()
|
||||
|
||||
for d in delayables:
|
||||
try:
|
||||
@ -193,6 +203,9 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
stop_modal_executor = True
|
||||
presence.renderer.stop()
|
||||
|
||||
if settings.update_method == 'DEPSGRAPH':
|
||||
bpy.app.handlers.depsgraph_update_post.remove(depsgraph_evaluation)
|
||||
|
||||
bpy.ops.session.apply_armature_operator()
|
||||
|
||||
self.report(
|
||||
@ -612,6 +625,39 @@ def update_client_frame(scene):
|
||||
'frame_current': scene.frame_current
|
||||
})
|
||||
|
||||
@persistent
|
||||
def depsgraph_evaluation(scene):
|
||||
if client and client.state['STATE'] == STATE_ACTIVE:
|
||||
context = bpy.context
|
||||
blender_depsgraph = bpy.context.view_layer.depsgraph
|
||||
dependency_updates = [u for u in blender_depsgraph.updates]
|
||||
session_infos = utils.get_preferences()
|
||||
|
||||
# NOTE: maybe we don't need to check each update but only the first
|
||||
|
||||
for update in reversed(dependency_updates):
|
||||
# Is the object tracked ?
|
||||
if update.id.uuid:
|
||||
# Retrieve local version
|
||||
node = client.get(update.id.uuid)
|
||||
|
||||
# Check our right on this update:
|
||||
# - if its ours or ( under common and diff), launch the
|
||||
# update process
|
||||
# - if its to someone else, ignore the update (go deeper ?)
|
||||
if node and node.owner in [client.id, RP_COMMON] and node.state == UP:
|
||||
# Avoid slow geometry update
|
||||
if 'EDIT' in context.mode:
|
||||
break
|
||||
|
||||
client.stash(node.uuid)
|
||||
else:
|
||||
# Distant update
|
||||
continue
|
||||
# else:
|
||||
# # New items !
|
||||
# logger.error("UPDATE: ADD")
|
||||
|
||||
|
||||
def register():
|
||||
from bpy.utils import register_class
|
||||
@ -625,6 +671,8 @@ def register():
|
||||
bpy.app.handlers.frame_change_pre.append(update_client_frame)
|
||||
|
||||
|
||||
|
||||
|
||||
def unregister():
|
||||
global client
|
||||
|
||||
@ -642,6 +690,3 @@ def unregister():
|
||||
bpy.app.handlers.load_pre.remove(load_pre_handler)
|
||||
bpy.app.handlers.frame_change_pre.remove(update_client_frame)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
@ -129,6 +129,19 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
description='connection timeout before disconnection',
|
||||
default=1000
|
||||
)
|
||||
update_method: bpy.props.EnumProperty(
|
||||
name='update method',
|
||||
description='replication update method',
|
||||
items=[
|
||||
('DEFAULT', "Default", "Default: Use threads to monitor databloc changes"),
|
||||
('DEPSGRAPH', "Depsgraph", "Experimental: Use the blender dependency graph to trigger updates"),
|
||||
],
|
||||
)
|
||||
depsgraph_update_rate: bpy.props.IntProperty(
|
||||
name='depsgraph update rate',
|
||||
description='Dependency graph uppdate rate (milliseconds)',
|
||||
default=100
|
||||
)
|
||||
# for UI
|
||||
category: bpy.props.EnumProperty(
|
||||
name="Category",
|
||||
@ -250,10 +263,13 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
box.row().prop(self, "ip", text="Address")
|
||||
row = box.row()
|
||||
row.label(text="Port:")
|
||||
row.prop(self, "port", text="Address")
|
||||
row.prop(self, "port", text="")
|
||||
row = box.row()
|
||||
row.label(text="Init the session from:")
|
||||
row.prop(self, "init_method", text="")
|
||||
row = box.row()
|
||||
row.label(text="Update method:")
|
||||
row.prop(self, "update_method", text="")
|
||||
|
||||
table = box.box()
|
||||
table.row().prop(
|
||||
|
@ -303,24 +303,32 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
replication_section_row.prop(settings.sync_flags, "sync_render_settings")
|
||||
|
||||
replication_section_row = replication_section.row()
|
||||
replication_section_row.label(text="Per data type timers:")
|
||||
replication_section_row.label(text="Update method:")
|
||||
replication_section_row.prop(settings, "update_method", text="")
|
||||
replication_section_row = replication_section.row()
|
||||
# Replication frequencies
|
||||
flow = replication_section_row .grid_flow(
|
||||
row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
line = flow.row(align=True)
|
||||
line.label(text=" ")
|
||||
line.separator()
|
||||
line.label(text="refresh (sec)")
|
||||
line.label(text="apply (sec)")
|
||||
|
||||
for item in settings.supported_datablocks:
|
||||
replication_timers = replication_section_row.box()
|
||||
replication_timers.label(text="Per data type timers", icon='TIME')
|
||||
if settings.update_method == "DEFAULT":
|
||||
replication_timers = replication_timers.row()
|
||||
# Replication frequencies
|
||||
flow = replication_timers.grid_flow(
|
||||
row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
line = flow.row(align=True)
|
||||
line.prop(item, "auto_push", text="", icon=item.icon)
|
||||
line.label(text=" ")
|
||||
line.separator()
|
||||
line.prop(item, "bl_delay_refresh", text="")
|
||||
line.prop(item, "bl_delay_apply", text="")
|
||||
line.label(text="refresh (sec)")
|
||||
line.label(text="apply (sec)")
|
||||
|
||||
for item in settings.supported_datablocks:
|
||||
line = flow.row(align=True)
|
||||
line.prop(item, "auto_push", text="", icon=item.icon)
|
||||
line.separator()
|
||||
line.prop(item, "bl_delay_refresh", text="")
|
||||
line.prop(item, "bl_delay_apply", text="")
|
||||
else:
|
||||
replication_timers = replication_timers.row()
|
||||
replication_timers.label(text="Update rate (ms):")
|
||||
replication_timers.prop(settings, "depsgraph_update_rate", text="")
|
||||
|
||||
class SESSION_PT_user(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_USER_PT_panel"
|
||||
|
Loading…
Reference in New Issue
Block a user