From fcf4604153512a64fa36808e9b35011b484acc2b Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 24 Jan 2020 17:52:10 +0100 Subject: [PATCH 01/39] feat: deps graph update handler --- multi_user/operators.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/multi_user/operators.py b/multi_user/operators.py index f5220db..f5ff741 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -473,6 +473,39 @@ def update_client_frame(scene): 'frame_current': scene.frame_current }) +@persistent +def depsgraph_evaluation(scene): + if client and client.state == STATE_ACTIVE: + context = bpy.context + blender_depsgraph = bpy.context.view_layer.depsgraph + dependency_updates = [u for u in blender_depsgraph.updates] + session_infos = bpy.context.window_manager.session + + # NOTE: maybe we don't need to check each update but only the first + # thanks to our deps graph.... + + 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.owner == session_infos.username: + # Avoid slow geometry update + if 'EDIT' in context.mode: + break + logger.error("UPDATE: MODIFIFY {}".format(type(update.id))) + else: + # Distant update + continue + # else: + # # New items ! + # logger.error("UPDATE: ADD")C.obj + def register(): from bpy.utils import register_class @@ -486,6 +519,8 @@ def register(): bpy.app.handlers.frame_change_pre.append(update_client_frame) + bpy.app.handlers.depsgraph_update_post.append(depsgraph_evaluation) + def unregister(): global client @@ -505,6 +540,8 @@ def unregister(): bpy.app.handlers.frame_change_pre.remove(update_client_frame) + bpy.app.handlers.depsgraph_update_post.remove(depsgraph_evaluation) + if __name__ == "__main__": register() From b6614768c431b2d6fc50ab1d4d43dbbbabbce827 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Mon, 3 Feb 2020 11:22:43 +0100 Subject: [PATCH 02/39] fix: mesh dumping performance --- multi_user/bl_types/bl_mesh.py | 17 ++++++++++------- multi_user/libs/replication | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/multi_user/bl_types/bl_mesh.py b/multi_user/bl_types/bl_mesh.py index 4fcce1d..c275208 100644 --- a/multi_user/bl_types/bl_mesh.py +++ b/multi_user/bl_types/bl_mesh.py @@ -11,6 +11,7 @@ def dump_mesh(mesh, data={}): mesh_data = data mesh_buffer = bmesh.new() + #https://blog.michelanders.nl/2016/02/copying-vertices-to-numpy-arrays-in_4.html mesh_buffer.from_mesh(mesh) uv_layer = mesh_buffer.loops.layers.uv.verify() @@ -72,7 +73,7 @@ def dump_mesh(mesh, data={}): uv_layers.append(uv_layer.name) mesh_data["uv_layers"] = uv_layers - return mesh_data + # return mesh_data class BlMesh(BlDatablock): bl_id = "meshes" @@ -87,12 +88,9 @@ class BlMesh(BlDatablock): instance.uuid = self.uuid return instance - def load(self, data, target): + def load_implementation(self, data, target): if not target or not target.is_editmode: # 1 - LOAD MATERIAL SLOTS - material_to_load = [] - material_to_load = utils.revers(data["materials"]) - target.materials.clear() # SLots i = 0 @@ -149,8 +147,13 @@ class BlMesh(BlDatablock): def dump_implementation(self, data, pointer=None): assert(pointer) - data = utils.dump_datablock(pointer, 2) - data = dump_mesh(pointer, data) + dumper = utils.dump_anything.Dumper() + dumper.depth = 2 + dumper.include_filter = [ + 'name', + ] + data = dumper.dump(pointer) + dump_mesh(pointer, data) # Fix material index m_list = [] for material in pointer.materials: diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 692a980..4fafa42 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 692a980b6d2b7f67475584366b4338663fbf5dea +Subproject commit 4fafa42ea82bbf90e66b8a207cb08e3a12530b8f From 6a667b074502c9c7f1c158db28051e63d4f939d6 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Mon, 3 Feb 2020 19:04:08 +0100 Subject: [PATCH 03/39] feat: experimental subprocess server --- multi_user/__init__.py | 2 +- multi_user/libs/replication | 2 +- multi_user/operators.py | 66 ++++++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/multi_user/__init__.py b/multi_user/__init__.py index 5ebdac2..8183054 100644 --- a/multi_user/__init__.py +++ b/multi_user/__init__.py @@ -244,7 +244,7 @@ classes = ( ) -libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication" +libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication\\replication" @persistent def load_handler(dummy): diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 4fafa42..ee4b406 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 4fafa42ea82bbf90e66b8a207cb08e3a12530b8f +Subproject commit ee4b4066e66b0f16d410f2871cf8b0893d343a0f diff --git a/multi_user/operators.py b/multi_user/operators.py index 2d6694c..d86358e 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -4,7 +4,7 @@ import os import queue import random import string -import subprocess +from subprocess import Popen, PIPE,TimeoutExpired import time from operator import itemgetter from pathlib import Path @@ -33,7 +33,7 @@ delayables = [] ui_context = None stop_modal_executor = False modal_executor_queue = None - +server_process = None # OPERATORS @@ -49,7 +49,7 @@ class SessionStartOperator(bpy.types.Operator): return True def execute(self, context): - global client, delayables, ui_context + global client, delayables, ui_context, server_process settings = context.window_manager.session users = bpy.data.window_managers['WinMan'].online_users @@ -80,10 +80,10 @@ class SessionStartOperator(bpy.types.Operator): timer=type_local_config.bl_delay_refresh, 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 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) @@ -92,16 +92,33 @@ class SessionStartOperator(bpy.types.Operator): if settings.start_empty: utils.clean_scene() + python = bpy.app.binary_path_python + server_path = bpy.utils.user_resource( 'SCRIPTS','addons\\multi_user\\libs\\replication\\server.py') + + server_process = Popen([python, server_path, '-p',str(settings.port)]) try: - client.host( - id=settings.username, - address=settings.ip, - port=settings.port, - right_strategy=settings.right_strategy - ) - except Exception as e: - self.report({'ERROR'}, repr(e)) - logger.error(f"Error: {e}") + outs, errs = server_process.communicate(timeout=1) + + if errs: + server_process.kill() + except TimeoutExpired: + pass + # try: + # client.host( + # id=settings.username, + # address=settings.ip, + # port=settings.port, + # right_strategy=settings.right_strategy + # ) + # except Exception as e: + # self.report({'ERROR'}, repr(e)) + # logger.error(f"Error: {e}") + + client.connect( + id=settings.username, + address=settings.ip, + port=settings.port + ) settings.is_admin = True else: @@ -128,13 +145,14 @@ class SessionStartOperator(bpy.types.Operator): # for node in client.list(): client.commit(scene_uuid) + # Push all added values + client.push_all() delayables.append(delayable.ClientUpdate()) delayables.append(delayable.DrawClient()) delayables.append(delayable.DynamicRightSelectTimer()) - # Push all added values - client.push_all() + # Launch drawing module if settings.enable_presence: @@ -165,7 +183,10 @@ class SessionStopOperator(bpy.types.Operator): return True def execute(self, context): - global client, delayables, stop_modal_executor + global client, delayables, stop_modal_executor, server_process + + if server_process: + server_process.kill() stop_modal_executor = True settings = context.window_manager.session @@ -444,7 +465,6 @@ classes = ( SessionCommit, ApplyArmatureOperator, - ) @@ -504,6 +524,8 @@ def depsgraph_evaluation(scene): if 'EDIT' in context.mode: break logger.error("UPDATE: MODIFIFY {}".format(type(update.id))) + client.commit(node.uuid) + client.push(node.uuid) else: # Distant update continue @@ -524,7 +546,7 @@ def register(): bpy.app.handlers.frame_change_pre.append(update_client_frame) - bpy.app.handlers.depsgraph_update_post.append(depsgraph_evaluation) + # bpy.app.handlers.depsgraph_update_post.append(depsgraph_evaluation) def unregister(): @@ -545,7 +567,7 @@ def unregister(): bpy.app.handlers.frame_change_pre.remove(update_client_frame) - bpy.app.handlers.depsgraph_update_post.remove(depsgraph_evaluation) + # bpy.app.handlers.depsgraph_update_post.remove(depsgraph_evaluation) if __name__ == "__main__": From 3b459d5387d0b6fd6d5ce48f04130b7a95834d79 Mon Sep 17 00:00:00 2001 From: Swann Date: Mon, 3 Feb 2020 23:18:53 +0100 Subject: [PATCH 04/39] refactor: cleanup --- log.txt | 1 - multi_user/operators.py | 18 ++++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 log.txt diff --git a/log.txt b/log.txt deleted file mode 100644 index 0cc3912..0000000 --- a/log.txt +++ /dev/null @@ -1 +0,0 @@ -{"area": null, "blend_data": \ No newline at end of file diff --git a/multi_user/operators.py b/multi_user/operators.py index d86358e..d801f02 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -80,10 +80,10 @@ class SessionStartOperator(bpy.types.Operator): timer=type_local_config.bl_delay_refresh, 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 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) @@ -103,16 +103,6 @@ class SessionStartOperator(bpy.types.Operator): server_process.kill() except TimeoutExpired: pass - # try: - # client.host( - # id=settings.username, - # address=settings.ip, - # port=settings.port, - # right_strategy=settings.right_strategy - # ) - # except Exception as e: - # self.report({'ERROR'}, repr(e)) - # logger.error(f"Error: {e}") client.connect( id=settings.username, From d1501da2f17ae9ae76600c53c96da0777fcce011 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Wed, 5 Feb 2020 16:33:21 +0100 Subject: [PATCH 05/39] feat: cleanup --- multi_user/libs/replication | 2 +- multi_user/operators.py | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index ee4b406..8744db4 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit ee4b4066e66b0f16d410f2871cf8b0893d343a0f +Subproject commit 8744db43ddb84f1cfd192ab2340e5af7e9c08ae7 diff --git a/multi_user/operators.py b/multi_user/operators.py index d801f02..9ed2260 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -4,26 +4,22 @@ import os import queue import random import string -from subprocess import Popen, PIPE,TimeoutExpired import time from operator import itemgetter from pathlib import Path -import msgpack +from subprocess import PIPE, Popen, TimeoutExpired import bpy import mathutils from bpy.app.handlers import persistent -from bpy_extras.io_utils import ExportHelper from . import bl_types, delayable, environment, presence, ui, utils +from .libs.replication.replication.constants import (FETCHED, STATE_ACTIVE, + STATE_INITIAL, + STATE_SYNCING) from .libs.replication.replication.data import ReplicatedDataFactory from .libs.replication.replication.exception import NonAuthorizedOperationError from .libs.replication.replication.interface import Session -from .libs.replication.replication.constants import ( - STATE_ACTIVE, - STATE_INITIAL, - STATE_SYNCING, - FETCHED) logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -94,8 +90,9 @@ class SessionStartOperator(bpy.types.Operator): python = bpy.app.binary_path_python server_path = bpy.utils.user_resource( 'SCRIPTS','addons\\multi_user\\libs\\replication\\server.py') - + server_process = Popen([python, server_path, '-p',str(settings.port)]) + try: outs, errs = server_process.communicate(timeout=1) From 4825e6876c0af7ad5e0e388a983c7ccbe6fde8dc Mon Sep 17 00:00:00 2001 From: Swann Date: Wed, 5 Feb 2020 23:26:53 +0100 Subject: [PATCH 06/39] feat: experiment bin diff for meshes --- multi_user/bl_types/bl_datablock.py | 4 +++- multi_user/bl_types/bl_mesh.py | 4 +++- multi_user/libs/replication | 2 +- multi_user/operators.py | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/multi_user/bl_types/bl_datablock.py b/multi_user/bl_types/bl_datablock.py index 2fdd203..f54cbb4 100644 --- a/multi_user/bl_types/bl_datablock.py +++ b/multi_user/bl_types/bl_datablock.py @@ -4,7 +4,7 @@ import mathutils from .. import utils from ..libs.replication.replication.data import ReplicatedDatablock from ..libs.replication.replication.constants import UP - +from ..libs.replication.replication.constants import DIFF_BINARY def dump_driver(driver): dumper = utils.dump_anything.Dumper() @@ -80,6 +80,8 @@ class BlDatablock(ReplicatedDatablock): if self.pointer and hasattr(self.pointer, 'uuid'): self.pointer.uuid = self.uuid + + self.diff_method = DIFF_BINARY def library_apply(self): """Apply stored data diff --git a/multi_user/bl_types/bl_mesh.py b/multi_user/bl_types/bl_mesh.py index c275208..e6ca629 100644 --- a/multi_user/bl_types/bl_mesh.py +++ b/multi_user/bl_types/bl_mesh.py @@ -3,6 +3,7 @@ import bmesh import mathutils from .. import utils + from .bl_datablock import BlDatablock def dump_mesh(mesh, data={}): @@ -81,9 +82,10 @@ class BlMesh(BlDatablock): bl_delay_refresh = 10 bl_delay_apply = 10 bl_automatic_push = True - bl_icon = 'MESH_DATA' + bl_icon = 'MESH_DATA' def construct(self, data): + instance = bpy.data.meshes.new(data["name"]) instance.uuid = self.uuid return instance diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 8744db4..39a52ac 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 8744db43ddb84f1cfd192ab2340e5af7e9c08ae7 +Subproject commit 39a52ac28cfd3e62336c560cf59305112a96b813 diff --git a/multi_user/operators.py b/multi_user/operators.py index 9ed2260..48d5a8e 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -511,8 +511,8 @@ def depsgraph_evaluation(scene): if 'EDIT' in context.mode: break logger.error("UPDATE: MODIFIFY {}".format(type(update.id))) - client.commit(node.uuid) - client.push(node.uuid) + # client.commit(node.uuid) + # client.push(node.uuid) else: # Distant update continue From 63294d2fd8409049798c4474296fa697f3983660 Mon Sep 17 00:00:00 2001 From: Swann Date: Wed, 5 Feb 2020 23:38:56 +0100 Subject: [PATCH 07/39] feat: update submodule version --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 39a52ac..0c837a1 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 39a52ac28cfd3e62336c560cf59305112a96b813 +Subproject commit 0c837a1577cbe3e2601fcfec835b7d6575d4aa7a From 6c47e727660a95ebcbfaec959419369fccab5082 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 6 Feb 2020 18:54:46 +0100 Subject: [PATCH 08/39] feat: big overal refactoring Added an orchestrator Removed ClienfEnventHandler Exposed IPC Port for local dev Relative to #59 --- multi_user/__init__.py | 5 +++++ multi_user/delayable.py | 6 +++--- multi_user/libs/replication | 2 +- multi_user/operators.py | 10 +++++++--- multi_user/ui.py | 6 ++++++ 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/multi_user/__init__.py b/multi_user/__init__.py index 8183054..5adeb86 100644 --- a/multi_user/__init__.py +++ b/multi_user/__init__.py @@ -118,6 +118,11 @@ class SessionProps(bpy.types.PropertyGroup): description='Distant host port', default=5555 ) + ttl_port: bpy.props.IntProperty( + name="ttl_port", + description='internal ttl port(only usefull for multiple local instances)', + default=5561 + ) is_admin: bpy.props.BoolProperty( name="is_admin", default=False diff --git a/multi_user/delayable.py b/multi_user/delayable.py index 0555c6b..6d78283 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -95,7 +95,7 @@ class DynamicRightSelectTimer(Timer): self._user = session.online_users.get(settings.username) if self._right_strategy is None: - self._right_strategy = session.get_config()[ + self._right_strategy = session.config[ 'right_strategy'] if self._user: @@ -233,8 +233,8 @@ class ClientUpdate(Timer): local_user_metadata = local_user.get('metadata') current_view_corners = presence.get_view_corners() - if not local_user_metadata: - logger.info("init user metadata") + if not local_user_metadata or 'color' not in local_user_metadata.keys(): + logger.error("init user metadata") metadata = { 'view_corners': current_view_corners, 'view_matrix': presence.get_view_matrix(), diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 0c837a1..240de8c 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 0c837a1577cbe3e2601fcfec835b7d6575d4aa7a +Subproject commit 240de8c6658faa1cf08c8b226e32acc7ffbaf1c6 diff --git a/multi_user/operators.py b/multi_user/operators.py index 48d5a8e..ef690ca 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -81,7 +81,9 @@ class SessionStartOperator(bpy.types.Operator): timout=type_local_config.bl_delay_apply, target_type=type_module_class)) - client = Session(factory=bpy_factory) + client = Session( + factory=bpy_factory, + python_path=bpy.app.binary_path_python) if self.host: # Scene setup @@ -104,7 +106,8 @@ class SessionStartOperator(bpy.types.Operator): client.connect( id=settings.username, address=settings.ip, - port=settings.port + port=settings.port, + ttl_port=settings.ttl_port ) settings.is_admin = True @@ -114,7 +117,8 @@ class SessionStartOperator(bpy.types.Operator): client.connect( id=settings.username, address=settings.ip, - port=settings.port + port=settings.port, + ttl_port=settings.ttl_port ) time.sleep(1) diff --git a/multi_user/ui.py b/multi_user/ui.py index 4890631..fab56ec 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -80,6 +80,9 @@ class SESSION_PT_settings_network(bpy.types.Panel): row.label(text="Port:") row.prop(settings, "port", text="") row = box.row() + row.label(text="IPC Port:") + row.prop(settings, "ttl_port", text="") + row = box.row() row.operator("session.start", text="HOST").host = True else: box = row.box() @@ -88,6 +91,9 @@ class SESSION_PT_settings_network(bpy.types.Panel): row = box.row() row.label(text="Port:") row.prop(settings, "port", text="") + row = box.row() + row.label(text="IPC Port:") + row.prop(settings, "ttl_port", text="") row = box.row() row.operator("session.start", text="CONNECT").host = False From cbdf8c94d71e19f3b76f440c7a8f3be10fa7b7d6 Mon Sep 17 00:00:00 2001 From: Swann Date: Thu, 6 Feb 2020 23:22:56 +0100 Subject: [PATCH 09/39] feat: submodule update --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 240de8c..63b8bf1 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 240de8c6658faa1cf08c8b226e32acc7ffbaf1c6 +Subproject commit 63b8bf198594e6b81051df5da75ec4feff7ba6d3 From 075388201562b32c22095f80a890936b69ed8a30 Mon Sep 17 00:00:00 2001 From: Swann Date: Fri, 7 Feb 2020 00:48:34 +0100 Subject: [PATCH 10/39] feat: lightprobe warning refactor: set logging default level to WARNING --- multi_user/__init__.py | 2 +- multi_user/bl_types/bl_lightprobe.py | 13 ++++++++++++- multi_user/bl_types/bl_object.py | 2 +- multi_user/delayable.py | 3 +-- multi_user/environment.py | 2 +- multi_user/operators.py | 2 +- multi_user/utils.py | 2 +- 7 files changed, 18 insertions(+), 8 deletions(-) diff --git a/multi_user/__init__.py b/multi_user/__init__.py index 5adeb86..78b34ff 100644 --- a/multi_user/__init__.py +++ b/multi_user/__init__.py @@ -31,7 +31,7 @@ DEPENDENCIES = { logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) #TODO: refactor config # UTILITY FUNCTIONS diff --git a/multi_user/bl_types/bl_lightprobe.py b/multi_user/bl_types/bl_lightprobe.py index 5298fe2..11e26d4 100644 --- a/multi_user/bl_types/bl_lightprobe.py +++ b/multi_user/bl_types/bl_lightprobe.py @@ -1,9 +1,11 @@ import bpy import mathutils +import logging from .. import utils from .bl_datablock import BlDatablock +logger = logging.getLogger(__name__) class BlLightprobe(BlDatablock): bl_id = "lightprobes" @@ -18,10 +20,19 @@ class BlLightprobe(BlDatablock): def construct(self, data): type = 'CUBE' if data['type'] == 'CUBEMAP' else data['type'] - return bpy.data.lightprobes.new(data["name"], type) + # See https://developer.blender.org/D6396 + if bpy.app.version[1] >= 83: + return bpy.data.lightprobes.new(data["name"], type) + else: + logger.warning("Lightprobe replication only supported since 2.83. See https://developer.blender.org/D6396") + + + def dump(self, pointer=None): assert(pointer) + if bpy.app.version[1] < 84: + logger.warning("Lightprobe replication only supported since 2.83. See https://developer.blender.org/D6396") dumper = utils.dump_anything.Dumper() dumper.depth = 1 diff --git a/multi_user/bl_types/bl_object.py b/multi_user/bl_types/bl_object.py index b812ff3..4ca7154 100644 --- a/multi_user/bl_types/bl_object.py +++ b/multi_user/bl_types/bl_object.py @@ -75,7 +75,7 @@ class BlObject(BlDatablock): if bpy.app.version[1] >= 83: pointer = bpy.data.lightprobes[data["data"]] else: - logger.error("Lightprobe replication only supported since 2.83") + logger.warning("Lightprobe replication only supported since 2.83. See https://developer.blender.org/D6396") instance = bpy.data.objects.new(data["name"], pointer) instance.uuid = self.uuid diff --git a/multi_user/delayable.py b/multi_user/delayable.py index 6d78283..29fe370 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -6,7 +6,7 @@ from . import operators, presence, utils from .libs.replication.replication.constants import FETCHED, RP_COMMON logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) class Delayable(): @@ -234,7 +234,6 @@ class ClientUpdate(Timer): current_view_corners = presence.get_view_corners() if not local_user_metadata or 'color' not in local_user_metadata.keys(): - logger.error("init user metadata") metadata = { 'view_corners': current_view_corners, 'view_matrix': presence.get_view_matrix(), diff --git a/multi_user/environment.py b/multi_user/environment.py index 8b5b7ca..67dec88 100644 --- a/multi_user/environment.py +++ b/multi_user/environment.py @@ -6,7 +6,7 @@ import sys from pathlib import Path logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) CONFIG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config") CONFIG = os.path.join(CONFIG_DIR, "app.yaml") diff --git a/multi_user/operators.py b/multi_user/operators.py index ef690ca..5d779c2 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -22,7 +22,7 @@ from .libs.replication.replication.exception import NonAuthorizedOperationError from .libs.replication.replication.interface import Session logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) client = None delayables = [] diff --git a/multi_user/utils.py b/multi_user/utils.py index 8cd35fb..7b8211a 100644 --- a/multi_user/utils.py +++ b/multi_user/utils.py @@ -14,7 +14,7 @@ from . import environment, presence from .libs import dump_anything logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) def has_action(target): return (hasattr(target, 'animation_data') From b0c195c34f5f7a12800d921e89b81000b903a219 Mon Sep 17 00:00:00 2001 From: Swann Date: Fri, 7 Feb 2020 00:49:04 +0100 Subject: [PATCH 11/39] feat: update submodule --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 63b8bf1..850456a 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 63b8bf198594e6b81051df5da75ec4feff7ba6d3 +Subproject commit 850456a004683db8dc811f5cd7c0d2dee580cc4a From 210e8aa0fa306e68df2ba7e2fde029bf13610878 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 10:39:12 +0100 Subject: [PATCH 12/39] feat: merged !12 changes (@c2ba) --- multi_user/bl_types/bl_image.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/multi_user/bl_types/bl_image.py b/multi_user/bl_types/bl_image.py index a968f78..3439a3c 100644 --- a/multi_user/bl_types/bl_image.py +++ b/multi_user/bl_types/bl_image.py @@ -15,8 +15,11 @@ def dump_image(image): image.save() if image.source == "FILE": + image_path = bpy.path.abspath(image.filepath_raw) + image_directory = os.path.dirname(image_path) + os.makedirs(image_directory, exist_ok=True) image.save() - file = open(image.filepath_raw, "rb") + file = open(image_path, "rb") pixels = file.read() file.close() else: From 5422518a475c50d3478c839ae7e5ebb8986af6ae Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 10:50:14 +0100 Subject: [PATCH 13/39] fix: lightprobe version support error --- multi_user/bl_types/bl_lightprobe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/bl_types/bl_lightprobe.py b/multi_user/bl_types/bl_lightprobe.py index 11e26d4..218ec8f 100644 --- a/multi_user/bl_types/bl_lightprobe.py +++ b/multi_user/bl_types/bl_lightprobe.py @@ -31,7 +31,7 @@ class BlLightprobe(BlDatablock): def dump(self, pointer=None): assert(pointer) - if bpy.app.version[1] < 84: + if bpy.app.version[1] < 83: logger.warning("Lightprobe replication only supported since 2.83. See https://developer.blender.org/D6396") dumper = utils.dump_anything.Dumper() From 2034773df6ea0b7824ef193e2a8a916677b226ed Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 11:34:23 +0100 Subject: [PATCH 14/39] fix: handle connexion error --- multi_user/libs/replication | 2 +- multi_user/operators.py | 22 ++++++---------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 850456a..0c28554 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 850456a004683db8dc811f5cd7c0d2dee580cc4a +Subproject commit 0c285547192ca31cd98ab1e6cc9b887d8a0d4ec9 diff --git a/multi_user/operators.py b/multi_user/operators.py index 5d779c2..3858579 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -103,33 +103,23 @@ class SessionStartOperator(bpy.types.Operator): except TimeoutExpired: pass - client.connect( - id=settings.username, - address=settings.ip, - port=settings.port, - ttl_port=settings.ttl_port - ) - settings.is_admin = True else: utils.clean_scene() + try: client.connect( id=settings.username, address=settings.ip, port=settings.port, ttl_port=settings.ttl_port ) + except Exception as e: + self.report({'ERROR'}, repr(e)) + logger.error(f"Error: {e}") - time.sleep(1) - - if client.state == 0: - settings.is_admin = False - self.report( - {'ERROR'}, - "A session is already hosted on this address") - return {"CANCELLED"} - + time.sleep(1) # Removed as soon as server will be launched from replication + if self.host: for scene in bpy.data.scenes: scene_uuid = client.add(scene) From 22eb65358b15402771bf5d1fc742e0734d39b561 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 14:11:23 +0100 Subject: [PATCH 15/39] feat: launch server from orchestrator --- multi_user/libs/replication | 2 +- multi_user/operators.py | 56 +++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 0c28554..44af43d 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 0c285547192ca31cd98ab1e6cc9b887d8a0d4ec9 +Subproject commit 44af43ddb4a08070c7d872abe08a781c682b0fde diff --git a/multi_user/operators.py b/multi_user/operators.py index 3858579..fe5dbb5 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -85,42 +85,28 @@ class SessionStartOperator(bpy.types.Operator): factory=bpy_factory, python_path=bpy.app.binary_path_python) + # Host a session if self.host: # Scene setup if settings.start_empty: utils.clean_scene() - python = bpy.app.binary_path_python - server_path = bpy.utils.user_resource( 'SCRIPTS','addons\\multi_user\\libs\\replication\\server.py') - - server_process = Popen([python, server_path, '-p',str(settings.port)]) - try: - outs, errs = server_process.communicate(timeout=1) - - if errs: - server_process.kill() - except TimeoutExpired: - pass + client.host( + id=settings.username, + address=settings.ip, + port=settings.port, + ttl_port=settings.ttl_port, + right_strategy=settings.right_strategy + ) + except Exception as e: + self.report({'ERROR'}, repr(e)) + logger.error(f"Error: {e}") settings.is_admin = True - else: - utils.clean_scene() - try: - client.connect( - id=settings.username, - address=settings.ip, - port=settings.port, - ttl_port=settings.ttl_port - ) - except Exception as e: - self.report({'ERROR'}, repr(e)) - logger.error(f"Error: {e}") - - time.sleep(1) # Removed as soon as server will be launched from replication - - if self.host: + time.sleep(2) # Removed as soon as server will be launched from replication + for scene in bpy.data.scenes: scene_uuid = client.add(scene) @@ -129,6 +115,22 @@ class SessionStartOperator(bpy.types.Operator): # Push all added values client.push_all() + # Join a session + else: + utils.clean_scene() + + try: + client.connect( + id=settings.username, + address=settings.ip, + port=settings.port, + ttl_port=settings.ttl_port + ) + except Exception as e: + self.report({'ERROR'}, repr(e)) + logger.error(f"Error: {e}") + + delayables.append(delayable.ClientUpdate()) delayables.append(delayable.DrawClient()) delayables.append(delayable.DynamicRightSelectTimer()) From 81752e9a2316a5769b8fb7a0ab71960c91649493 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 17:08:36 +0100 Subject: [PATCH 16/39] fix: delayable from accessing session data before its ready refactor: remove feat: submodule update --- multi_user/delayable.py | 21 ++++++++--------- multi_user/libs/replication | 2 +- multi_user/operators.py | 45 ++++++++++++++++--------------------- multi_user/ui.py | 2 +- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/multi_user/delayable.py b/multi_user/delayable.py index 29fe370..48146cf 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -3,7 +3,7 @@ import logging import bpy from . import operators, presence, utils -from .libs.replication.replication.constants import FETCHED, RP_COMMON +from .libs.replication.replication.constants import FETCHED, RP_COMMON, STATE_ACTIVE logger = logging.getLogger(__name__) logger.setLevel(logging.WARNING) @@ -89,7 +89,7 @@ class DynamicRightSelectTimer(Timer): session = operators.client settings = bpy.context.window_manager.session - if session: + if session and session.state == STATE_ACTIVE: # Find user if self._user is None: self._user = session.online_users.get(settings.username) @@ -195,19 +195,20 @@ class DrawClient(Draw): session = getattr(operators, 'client', None) renderer = getattr(presence, 'renderer', None) - if session and renderer: + if session and renderer and session.state == STATE_ACTIVE: settings = bpy.context.window_manager.session users = session.online_users for user in users.values(): metadata = user.get('metadata') - if settings.presence_show_selected and 'selected_objects' in metadata.keys(): - renderer.draw_client_selection( - user['id'], metadata['color'], metadata['selected_objects']) - if settings.presence_show_user and 'view_corners' in metadata: - renderer.draw_client_camera( - user['id'], metadata['view_corners'], metadata['color']) + if 'color' in metadata: + if settings.presence_show_selected and 'selected_objects' in metadata.keys(): + renderer.draw_client_selection( + user['id'], metadata['color'], metadata['selected_objects']) + if settings.presence_show_user and 'view_corners' in metadata: + renderer.draw_client_camera( + user['id'], metadata['view_corners'], metadata['color']) class ClientUpdate(Timer): @@ -220,7 +221,7 @@ class ClientUpdate(Timer): session = getattr(operators, 'client', None) renderer = getattr(presence, 'renderer', None) - if session and renderer: + if session and renderer and session.state == STATE_ACTIVE: # Check if session has been closes prematurely if session.state == 0: bpy.ops.session.stop() diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 44af43d..d0f2338 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 44af43ddb4a08070c7d872abe08a781c682b0fde +Subproject commit d0f2338fb62f2b21dba4ed4737ecaa2b28a9e2ff diff --git a/multi_user/operators.py b/multi_user/operators.py index fe5dbb5..503e5ca 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -83,7 +83,8 @@ class SessionStartOperator(bpy.types.Operator): client = Session( factory=bpy_factory, - python_path=bpy.app.binary_path_python) + python_path=bpy.app.binary_path_python, + default_strategy=settings.right_strategy) # Host a session if self.host: @@ -92,29 +93,21 @@ class SessionStartOperator(bpy.types.Operator): utils.clean_scene() try: + for scene in bpy.data.scenes: + scene_uuid = client.add(scene) + client.commit(scene_uuid) + client.host( id=settings.username, address=settings.ip, port=settings.port, - ttl_port=settings.ttl_port, - right_strategy=settings.right_strategy - ) + ttl_port=settings.ttl_port) except Exception as e: self.report({'ERROR'}, repr(e)) logger.error(f"Error: {e}") settings.is_admin = True - time.sleep(2) # Removed as soon as server will be launched from replication - - for scene in bpy.data.scenes: - scene_uuid = client.add(scene) - - # for node in client.list(): - client.commit(scene_uuid) - # Push all added values - client.push_all() - # Join a session else: utils.clean_scene() @@ -130,13 +123,12 @@ class SessionStartOperator(bpy.types.Operator): self.report({'ERROR'}, repr(e)) logger.error(f"Error: {e}") - + # Background client updates service + #TODO: Refactoring delayables.append(delayable.ClientUpdate()) delayables.append(delayable.DrawClient()) delayables.append(delayable.DynamicRightSelectTimer()) - - # Launch drawing module if settings.enable_presence: presence.renderer.run() @@ -408,17 +400,18 @@ class ApplyArmatureOperator(bpy.types.Operator): if event.type == 'TIMER': global client - nodes = client.list(filter=bl_types.bl_armature.BlArmature) + if client.state == STATE_ACTIVE: + nodes = client.list(filter=bl_types.bl_armature.BlArmature) - for node in nodes: - node_ref = client.get(uuid=node) + for node in nodes: + node_ref = client.get(uuid=node) - if node_ref.state == FETCHED: - try: - client.apply(node) - except Exception as e: - logger.error( - "fail to apply {}: {}".format(node_ref.uuid, e)) + if node_ref.state == FETCHED: + try: + client.apply(node) + except Exception as e: + logger.error( + "fail to apply {}: {}".format(node_ref.uuid, e)) return {'PASS_THROUGH'} diff --git a/multi_user/ui.py b/multi_user/ui.py index fab56ec..327c43c 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -229,7 +229,7 @@ class SESSION_UL_users(bpy.types.UIList): if user: ping = str(user['latency']) metadata = user.get('metadata') - if metadata: + if metadata and 'frame_current' in metadata: frame_current = str(metadata['frame_current']) split = layout.split(factor=0.5) From 8a2d178a4f5e429b1ad8974e0fec7e2088f4661b Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 17:56:58 +0100 Subject: [PATCH 17/39] refactor: state with progression ! --- multi_user/delayable.py | 8 +++---- multi_user/libs/replication | 2 +- multi_user/operators.py | 12 +++++----- multi_user/ui.py | 45 ++++++++++++++++++++++++++++--------- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/multi_user/delayable.py b/multi_user/delayable.py index 48146cf..8dcdcce 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -89,7 +89,7 @@ class DynamicRightSelectTimer(Timer): session = operators.client settings = bpy.context.window_manager.session - if session and session.state == STATE_ACTIVE: + if session and session.state['STATE'] == STATE_ACTIVE: # Find user if self._user is None: self._user = session.online_users.get(settings.username) @@ -195,7 +195,7 @@ class DrawClient(Draw): session = getattr(operators, 'client', None) renderer = getattr(presence, 'renderer', None) - if session and renderer and session.state == STATE_ACTIVE: + if session and renderer and session.state['STATE'] == STATE_ACTIVE: settings = bpy.context.window_manager.session users = session.online_users @@ -221,9 +221,9 @@ class ClientUpdate(Timer): session = getattr(operators, 'client', None) renderer = getattr(presence, 'renderer', None) - if session and renderer and session.state == STATE_ACTIVE: + if session and renderer and session.state['STATE'] == STATE_ACTIVE: # Check if session has been closes prematurely - if session.state == 0: + if session.state['STATE'] == 0: bpy.ops.session.stop() local_user = operators.client.online_users.get( diff --git a/multi_user/libs/replication b/multi_user/libs/replication index d0f2338..5a5571d 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit d0f2338fb62f2b21dba4ed4737ecaa2b28a9e2ff +Subproject commit 5a5571d943a1cb8a4b26e9397d0ced42acbea938 diff --git a/multi_user/operators.py b/multi_user/operators.py index 503e5ca..db8b2bc 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -400,7 +400,7 @@ class ApplyArmatureOperator(bpy.types.Operator): if event.type == 'TIMER': global client - if client.state == STATE_ACTIVE: + if client.state['STATE'] == STATE_ACTIVE: nodes = client.list(filter=bl_types.bl_armature.BlArmature) for node in nodes: @@ -448,7 +448,7 @@ classes = ( def load_pre_handler(dummy): global client - if client and client.state in [STATE_ACTIVE, STATE_SYNCING]: + if client and client.state['STATE'] in [STATE_ACTIVE, STATE_SYNCING]: bpy.ops.session.stop() @@ -462,21 +462,21 @@ def sanitize_deps_graph(dummy): """ global client - if client and client.state in [STATE_ACTIVE]: + if client and client.state['STATE'] in [STATE_ACTIVE]: for node_key in client.list(): client.get(node_key).resolve() @persistent def update_client_frame(scene): - if client and client.state == STATE_ACTIVE: + if client and client.state['STATE'] == STATE_ACTIVE: client.update_user_metadata({ 'frame_current': scene.frame_current }) @persistent def depsgraph_evaluation(scene): - if client and client.state == STATE_ACTIVE: + 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] @@ -528,7 +528,7 @@ def register(): def unregister(): global client - if client and client.state == 2: + if client and client.state['STATE'] == 2: client.disconnect() client = None diff --git a/multi_user/ui.py b/multi_user/ui.py index 327c43c..f099714 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -2,7 +2,11 @@ import bpy from . import operators from .libs.replication.replication.constants import (ADDED, ERROR, FETCHED, - MODIFIED, RP_COMMON, UP) + MODIFIED, RP_COMMON, UP, + STATE_ACTIVE, STATE_AUTH, + STATE_CONFIG, STATE_SYNCING, + STATE_INITIAL, STATE_SRV_SYNC, + STATE_WAITING) ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED 'TRIA_UP', # COMMITED @@ -11,6 +15,21 @@ ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED 'FILE_REFRESH', # UP 'TRIA_UP'] # CHANGED +def get_state_str(state): + state_str = 'None' + if state == STATE_WAITING: + state_str = 'WAITING' + elif state == STATE_SYNCING: + state_str = 'SYNCING' + elif state == STATE_AUTH: + state_str = 'AUTHENTIFICATION' + elif state == STATE_CONFIG: + state_str = 'CONFIGURATION' + elif state == STATE_ACTIVE: + state_str = 'ACTIVE' + elif state == STATE_SRV_SYNC: + state_str = 'SERVER SYNC' + return state_str class SESSION_PT_settings(bpy.types.Panel): """Settings panel""" @@ -31,19 +50,25 @@ class SESSION_PT_settings(bpy.types.Panel): if hasattr(context.window_manager, 'session'): # STATE INITIAL if not operators.client \ - or (operators.client and operators.client.state == 0): + or (operators.client and operators.client.state['STATE'] == STATE_INITIAL): pass else: + cli_state = operators.client.state # STATE ACTIVE - if operators.client.state == 2: + if cli_state['STATE'] == STATE_ACTIVE: row = layout.row() row.operator("session.stop", icon='QUIT', text="Exit") row = layout.row() # STATE SYNCING else: - status = "connecting..." - row.label(text=status) + row.label(text='Connecting:') + row = layout.row() + row.label(text=f"{get_state_str(cli_state['STATE'])}") + row = layout.row() + + if cli_state['STATE'] in [STATE_SYNCING,STATE_SRV_SYNC]: + row.label(text=f"{cli_state['CURRENT']}/{cli_state['TOTAL']}") row = layout.row() row.operator("session.stop", icon='QUIT', text="CANCEL") @@ -59,7 +84,7 @@ class SESSION_PT_settings_network(bpy.types.Panel): @classmethod def poll(cls, context): return not operators.client \ - or (operators.client and operators.client.state == 0) + or (operators.client and operators.client.state['STATE'] == 0) def draw(self, context): layout = self.layout @@ -110,7 +135,7 @@ class SESSION_PT_settings_user(bpy.types.Panel): @classmethod def poll(cls, context): return not operators.client \ - or (operators.client and operators.client.state == 0) + or (operators.client and operators.client.state['STATE'] == 0) def draw(self, context): layout = self.layout @@ -138,7 +163,7 @@ class SESSION_PT_settings_replication(bpy.types.Panel): @classmethod def poll(cls, context): return not operators.client \ - or (operators.client and operators.client.state == 0) + or (operators.client and operators.client.state['STATE'] == 0) def draw(self, context): layout = self.layout @@ -180,7 +205,7 @@ class SESSION_PT_user(bpy.types.Panel): @classmethod def poll(cls, context): - return operators.client and operators.client.state == 2 + return operators.client and operators.client.state['STATE'] == 2 def draw(self, context): layout = self.layout @@ -336,7 +361,7 @@ class SESSION_PT_outliner(bpy.types.Panel): @classmethod def poll(cls, context): - return operators.client and operators.client.state == 2 + return operators.client and operators.client.state['STATE'] == 2 def draw_header(self, context): self.layout.label(text="", icon='OUTLINER_OB_GROUP_INSTANCE') From b182632723caa91774d4a369aaa5cfd9561e2204 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 7 Feb 2020 18:09:33 +0100 Subject: [PATCH 18/39] feat: show basic progress --- multi_user/libs/replication | 2 +- multi_user/ui.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 5a5571d..425d2c1 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 5a5571d943a1cb8a4b26e9397d0ced42acbea938 +Subproject commit 425d2c13824945dacb2f88d5fbfe51950565abf5 diff --git a/multi_user/ui.py b/multi_user/ui.py index f099714..3296e89 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -18,7 +18,7 @@ ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED def get_state_str(state): state_str = 'None' if state == STATE_WAITING: - state_str = 'WAITING' + state_str = 'COMMITING DATA' elif state == STATE_SYNCING: state_str = 'SYNCING' elif state == STATE_AUTH: @@ -67,7 +67,7 @@ class SESSION_PT_settings(bpy.types.Panel): row.label(text=f"{get_state_str(cli_state['STATE'])}") row = layout.row() - if cli_state['STATE'] in [STATE_SYNCING,STATE_SRV_SYNC]: + if cli_state['STATE'] in [STATE_SYNCING,STATE_SRV_SYNC,STATE_WAITING]: row.label(text=f"{cli_state['CURRENT']}/{cli_state['TOTAL']}") row = layout.row() row.operator("session.stop", icon='QUIT', text="CANCEL") From 378f52a1abb5c988d6d90ecd616db2f5f90fac21 Mon Sep 17 00:00:00 2001 From: Swann Date: Sat, 8 Feb 2020 23:23:00 +0100 Subject: [PATCH 19/39] fix: mesh uv loading issue refacotr: loading status refactor: cleanup logs --- multi_user/bl_types/bl_datablock.py | 2 -- multi_user/bl_types/bl_mesh.py | 10 ++++++---- multi_user/libs/replication | 2 +- multi_user/ui.py | 9 +++++---- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/multi_user/bl_types/bl_datablock.py b/multi_user/bl_types/bl_datablock.py index f54cbb4..a39558e 100644 --- a/multi_user/bl_types/bl_datablock.py +++ b/multi_user/bl_types/bl_datablock.py @@ -80,8 +80,6 @@ class BlDatablock(ReplicatedDatablock): if self.pointer and hasattr(self.pointer, 'uuid'): self.pointer.uuid = self.uuid - - self.diff_method = DIFF_BINARY def library_apply(self): """Apply stored data diff --git a/multi_user/bl_types/bl_mesh.py b/multi_user/bl_types/bl_mesh.py index e6ca629..888ba31 100644 --- a/multi_user/bl_types/bl_mesh.py +++ b/multi_user/bl_types/bl_mesh.py @@ -3,7 +3,7 @@ import bmesh import mathutils from .. import utils - +from ..libs.replication.replication.constants import DIFF_BINARY from .bl_datablock import BlDatablock def dump_mesh(mesh, data={}): @@ -85,7 +85,7 @@ class BlMesh(BlDatablock): bl_icon = 'MESH_DATA' def construct(self, data): - + self.diff_method = DIFF_BINARY instance = bpy.data.meshes.new(data["name"]) instance.uuid = self.uuid return instance @@ -136,8 +136,10 @@ class BlMesh(BlDatablock): # 3 - LOAD METADATA # uv's - for uv_layer in data['uv_layers']: - target.uv_layers.new(name=uv_layer) + # target.uv_layers.clear() + utils.dump_anything.load(target.uv_layers, data['uv_layers']) + # for uv_layer in data['uv_layers']: + # target.uv_layers.new(name=uv_layer) bevel_layer = mesh_buffer.verts.layers.bevel_weight.verify() skin_layer = mesh_buffer.verts.layers.skin.verify() diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 425d2c1..226ca7c 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 425d2c13824945dacb2f88d5fbfe51950565abf5 +Subproject commit 226ca7cd8a343ef9e566fca4bda4a51f3b50a82f diff --git a/multi_user/ui.py b/multi_user/ui.py index 3296e89..e7009d0 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -18,9 +18,9 @@ ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED def get_state_str(state): state_str = 'None' if state == STATE_WAITING: - state_str = 'COMMITING DATA' + state_str = 'WRMING UP DATA' elif state == STATE_SYNCING: - state_str = 'SYNCING' + state_str = 'FETCHING FROM SERVER' elif state == STATE_AUTH: state_str = 'AUTHENTIFICATION' elif state == STATE_CONFIG: @@ -28,7 +28,7 @@ def get_state_str(state): elif state == STATE_ACTIVE: state_str = 'ACTIVE' elif state == STATE_SRV_SYNC: - state_str = 'SERVER SYNC' + state_str = 'PUSHING TO SERVER' return state_str class SESSION_PT_settings(bpy.types.Panel): @@ -274,7 +274,8 @@ class SESSION_PT_presence(bpy.types.Panel): @classmethod def poll(cls, context): - return True + return not operators.client \ + or (operators.client and operators.client.state['STATE'] in [STATE_INITIAL, STATE_ACTIVE]) def draw_header(self, context): self.layout.prop(context.window_manager.session, "enable_presence", text="") From c42c0cb017c122f3c69bb4979d83a0c5c427d46a Mon Sep 17 00:00:00 2001 From: Swann Date: Sat, 8 Feb 2020 23:25:37 +0100 Subject: [PATCH 20/39] refactor: cleanup --- multi_user/bl_types/bl_mesh.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/multi_user/bl_types/bl_mesh.py b/multi_user/bl_types/bl_mesh.py index 888ba31..97c5336 100644 --- a/multi_user/bl_types/bl_mesh.py +++ b/multi_user/bl_types/bl_mesh.py @@ -6,13 +6,14 @@ from .. import utils from ..libs.replication.replication.constants import DIFF_BINARY from .bl_datablock import BlDatablock + def dump_mesh(mesh, data={}): import bmesh mesh_data = data mesh_buffer = bmesh.new() - #https://blog.michelanders.nl/2016/02/copying-vertices-to-numpy-arrays-in_4.html + # https://blog.michelanders.nl/2016/02/copying-vertices-to-numpy-arrays-in_4.html mesh_buffer.from_mesh(mesh) uv_layer = mesh_buffer.loops.layers.uv.verify() @@ -76,13 +77,14 @@ def dump_mesh(mesh, data={}): mesh_data["uv_layers"] = uv_layers # return mesh_data + class BlMesh(BlDatablock): bl_id = "meshes" bl_class = bpy.types.Mesh bl_delay_refresh = 10 bl_delay_apply = 10 bl_automatic_push = True - bl_icon = 'MESH_DATA' + bl_icon = 'MESH_DATA' def construct(self, data): self.diff_method = DIFF_BINARY @@ -95,7 +97,7 @@ class BlMesh(BlDatablock): # 1 - LOAD MATERIAL SLOTS # SLots i = 0 - + for m in data["material_list"]: target.materials.append(bpy.data.materials[m]) @@ -106,7 +108,7 @@ class BlMesh(BlDatablock): v = mesh_buffer.verts.new(data["verts"][i]["co"]) v.normal = data["verts"][i]["normal"] mesh_buffer.verts.ensure_lookup_table() - + for i in data["edges"]: verts = mesh_buffer.verts v1 = data["edges"][i]["verts"][0] @@ -117,12 +119,12 @@ class BlMesh(BlDatablock): verts = [] for v in data["faces"][p]["verts"]: verts.append(mesh_buffer.verts[v]) - + if len(verts) > 0: f = mesh_buffer.faces.new(verts) - + uv_layer = mesh_buffer.loops.layers.uv.verify() - + f.smooth = data["faces"][p]["smooth"] f.normal = data["faces"][p]["normal"] f.index = data["faces"][p]["index"] @@ -136,17 +138,12 @@ class BlMesh(BlDatablock): # 3 - LOAD METADATA # uv's - # target.uv_layers.clear() utils.dump_anything.load(target.uv_layers, data['uv_layers']) - # for uv_layer in data['uv_layers']: - # target.uv_layers.new(name=uv_layer) - + bevel_layer = mesh_buffer.verts.layers.bevel_weight.verify() skin_layer = mesh_buffer.verts.layers.skin.verify() - + utils.dump_anything.load(target, data) - - def dump_implementation(self, data, pointer=None): assert(pointer) @@ -170,13 +167,12 @@ class BlMesh(BlDatablock): def resolve_dependencies(self): deps = [] - + for material in self.pointer.materials: if material: deps.append(material) - + return deps - + def is_valid(self): return bpy.data.meshes.get(self.data['name']) - From 6975edfb66deb91a7b10a994dcafd9c7e94bb290 Mon Sep 17 00:00:00 2001 From: Swann Date: Sun, 9 Feb 2020 00:41:00 +0100 Subject: [PATCH 21/39] feat: simple progress bar --- multi_user/delayable.py | 7 +++++-- multi_user/ui.py | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/multi_user/delayable.py b/multi_user/delayable.py index 8dcdcce..b3af08c 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -3,7 +3,7 @@ import logging import bpy from . import operators, presence, utils -from .libs.replication.replication.constants import FETCHED, RP_COMMON, STATE_ACTIVE +from .libs.replication.replication.constants import FETCHED, RP_COMMON, STATE_ACTIVE, STATE_SYNCING, STATE_SRV_SYNC logger = logging.getLogger(__name__) logger.setLevel(logging.WARNING) @@ -212,7 +212,7 @@ class DrawClient(Draw): class ClientUpdate(Timer): - def __init__(self, timout=1): + def __init__(self, timout=.5): super().__init__(timout) def execute(self): @@ -273,3 +273,6 @@ class ClientUpdate(Timer): # TODO: event drivent 3d view refresh presence.refresh_3d_view() + # ui update + elif session: + presence.refresh_3d_view() \ No newline at end of file diff --git a/multi_user/ui.py b/multi_user/ui.py index e7009d0..bb647e9 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -15,10 +15,27 @@ ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED 'FILE_REFRESH', # UP 'TRIA_UP'] # CHANGED +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', fill_empty=' '): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + fill_empty * (length - filledLength) + return '{} |{}| {}%{}'.format(prefix, bar, percent, suffix) + def get_state_str(state): state_str = 'None' if state == STATE_WAITING: - state_str = 'WRMING UP DATA' + state_str = 'WARMING UP DATA' elif state == STATE_SYNCING: state_str = 'FETCHING FROM SERVER' elif state == STATE_AUTH: @@ -26,7 +43,7 @@ def get_state_str(state): elif state == STATE_CONFIG: state_str = 'CONFIGURATION' elif state == STATE_ACTIVE: - state_str = 'ACTIVE' + state_str = 'ONLINE' elif state == STATE_SRV_SYNC: state_str = 'PUSHING TO SERVER' return state_str @@ -54,21 +71,25 @@ class SESSION_PT_settings(bpy.types.Panel): pass else: cli_state = operators.client.state + + row.label(text=f"Status : {get_state_str(cli_state['STATE'])}") + row = layout.row() + # STATE ACTIVE if cli_state['STATE'] == STATE_ACTIVE: - row = layout.row() row.operator("session.stop", icon='QUIT', text="Exit") row = layout.row() # STATE SYNCING else: - row.label(text='Connecting:') - row = layout.row() - row.label(text=f"{get_state_str(cli_state['STATE'])}") - row = layout.row() - + box = row.box() if cli_state['STATE'] in [STATE_SYNCING,STATE_SRV_SYNC,STATE_WAITING]: - row.label(text=f"{cli_state['CURRENT']}/{cli_state['TOTAL']}") + box.label(text=printProgressBar( + cli_state['CURRENT'], + cli_state['TOTAL'], + length=16 + )) + row = layout.row() row.operator("session.stop", icon='QUIT', text="CANCEL") From af53e54aa80ff156d3aa41720c20cb8221335f81 Mon Sep 17 00:00:00 2001 From: Swann Date: Sun, 9 Feb 2020 00:55:19 +0100 Subject: [PATCH 22/39] refactor: progress bar update --- multi_user/libs/replication | 2 +- multi_user/ui.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 226ca7c..6893e55 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 226ca7cd8a343ef9e566fca4bda4a51f3b50a82f +Subproject commit 6893e55a828e950af03a68e0e3dd28fb61a9e162 diff --git a/multi_user/ui.py b/multi_user/ui.py index bb647e9..f11e985 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -30,7 +30,7 @@ def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) bar = fill * filledLength + fill_empty * (length - filledLength) - return '{} |{}| {}%{}'.format(prefix, bar, percent, suffix) + return '{} |{}| {}/{}{}'.format(prefix, bar, iteration,total, suffix) def get_state_str(state): state_str = 'None' From 65525ca2e1a2cce1e157b98db0a38dbeea702e9b Mon Sep 17 00:00:00 2001 From: Swann Date: Sun, 9 Feb 2020 23:37:02 +0100 Subject: [PATCH 23/39] feat: notice --- multi_user/ui.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/multi_user/ui.py b/multi_user/ui.py index f11e985..75e4716 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -26,6 +26,8 @@ def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, decimals - Optional : positive number of decimals in percent complete (Int) length - Optional : character length of bar (Int) fill - Optional : bar fill character (Str) + From here: + https://gist.github.com/greenstick/b23e475d2bfdc3a82e34eaa1f6781ee4 """ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) From f1020fb072c14bbcaca446a3f25a15939418f841 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 14 Feb 2020 16:02:30 +0100 Subject: [PATCH 24/39] feat: prevent apply before session in active --- multi_user/delayable.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/multi_user/delayable.py b/multi_user/delayable.py index b3af08c..07578e8 100644 --- a/multi_user/delayable.py +++ b/multi_user/delayable.py @@ -64,15 +64,16 @@ class ApplyTimer(Timer): super().__init__(timout) def execute(self): - if operators.client: - nodes = operators.client.list(filter=self._type) + client = operators.client + if client and client.state['STATE'] == STATE_ACTIVE: + nodes = client.list(filter=self._type) for node in nodes: - node_ref = operators.client.get(uuid=node) + node_ref = client.get(uuid=node) if node_ref.state == FETCHED: try: - operators.client.apply(node) + client.apply(node) except Exception as e: logger.error( "fail to apply {}: {}".format(node_ref.uuid, e)) From 6a0705a73e918148ef4579d02de8409899a743e1 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 14 Feb 2020 16:44:53 +0100 Subject: [PATCH 25/39] feat: increase snap timer refresh rate fix (replication): unknown user state update --- multi_user/libs/replication | 2 +- multi_user/operators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 6893e55..3372b26 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 6893e55a828e950af03a68e0e3dd28fb61a9e162 +Subproject commit 3372b267a942f631c7ebdcb2a4791dfcf8aa9aad diff --git a/multi_user/operators.py b/multi_user/operators.py index db8b2bc..37b4508 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -317,7 +317,7 @@ class SessionSnapTimeOperator(bpy.types.Operator): settings.user_snap_running = True wm = context.window_manager - self._timer = wm.event_timer_add(0.1, window=context.window) + self._timer = wm.event_timer_add(0.05, window=context.window) wm.modal_handler_add(self) return {'RUNNING_MODAL'} From 5f2dca4032639f4ce16bd253bc72f41f23f66bb9 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 14 Feb 2020 16:54:51 +0100 Subject: [PATCH 26/39] feat: update submodule --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 3372b26..e2443a0 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 3372b267a942f631c7ebdcb2a4791dfcf8aa9aad +Subproject commit e2443a0173bc261238706bee0110d26e20b81fcc From b9d144f24a1de9972bec8c18dae27a058ad3ad8e Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Wed, 19 Feb 2020 16:22:06 +0100 Subject: [PATCH 27/39] feat: services basic ui to track services states --- multi_user/libs/replication | 2 +- multi_user/operators.py | 2 +- multi_user/ui.py | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index e2443a0..6accb22 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit e2443a0173bc261238706bee0110d26e20b81fcc +Subproject commit 6accb222a34190f74d96837dcba897228f7f96e9 diff --git a/multi_user/operators.py b/multi_user/operators.py index 37b4508..a4e979b 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -117,7 +117,7 @@ class SessionStartOperator(bpy.types.Operator): id=settings.username, address=settings.ip, port=settings.port, - ttl_port=settings.ttl_port + ipc_port=settings.ttl_port ) except Exception as e: self.report({'ERROR'}, repr(e)) diff --git a/multi_user/ui.py b/multi_user/ui.py index 75e4716..5e7e1f0 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -48,6 +48,8 @@ def get_state_str(state): state_str = 'ONLINE' elif state == STATE_SRV_SYNC: state_str = 'PUSHING TO SERVER' + elif state == STATE_INITIAL: + state_str = 'INIT' return state_str class SESSION_PT_settings(bpy.types.Panel): @@ -313,6 +315,34 @@ class SESSION_PT_presence(bpy.types.Panel): col.prop(settings,"presence_show_user") row = layout.row() +class SESSION_PT_services(bpy.types.Panel): + bl_idname = "MULTIUSER_SERVICE_PT_panel" + bl_label = "Services" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "Multiuser" + bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel' + + @classmethod + def poll(cls, context): + return operators.client and operators.client.state['STATE'] == 2 + + def draw(self, context): + layout = self.layout + online_users = context.window_manager.online_users + selected_user = context.window_manager.user_index + settings = context.window_manager.session + active_user = online_users[selected_user] if len(online_users)-1>=selected_user else 0 + + + # Create a simple row. + row = layout.row() + for name, state in operators.client.services_state.items(): + row.label(text=name) + row.label(text=get_state_str(state)) + row = layout.row() + + def draw_property(context, parent, property_uuid, level=0): settings = context.window_manager.session @@ -440,7 +470,8 @@ classes = ( SESSION_PT_presence, SESSION_PT_settings_replication, SESSION_PT_user, - SESSION_PT_outliner + SESSION_PT_outliner, + SESSION_PT_services ) From 2d352ec14a5becb6552c9f30c25cdce9b6389ad1 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Wed, 19 Feb 2020 18:07:25 +0100 Subject: [PATCH 28/39] feat: show basic service states in ui --- multi_user/__init__.py | 4 ++-- multi_user/libs/replication | 2 +- multi_user/operators.py | 4 ++-- multi_user/ui.py | 33 +++++++++++++-------------------- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/multi_user/__init__.py b/multi_user/__init__.py index 78b34ff..ef130a4 100644 --- a/multi_user/__init__.py +++ b/multi_user/__init__.py @@ -118,8 +118,8 @@ class SessionProps(bpy.types.PropertyGroup): description='Distant host port', default=5555 ) - ttl_port: bpy.props.IntProperty( - name="ttl_port", + ipc_port: bpy.props.IntProperty( + name="ipc_port", description='internal ttl port(only usefull for multiple local instances)', default=5561 ) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 6accb22..9e00109 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 6accb222a34190f74d96837dcba897228f7f96e9 +Subproject commit 9e0010993325f1d51fbf8f13b2b7053c002b48b3 diff --git a/multi_user/operators.py b/multi_user/operators.py index a4e979b..948ab04 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -101,7 +101,7 @@ class SessionStartOperator(bpy.types.Operator): id=settings.username, address=settings.ip, port=settings.port, - ttl_port=settings.ttl_port) + ipc_port=settings.ipc_port) except Exception as e: self.report({'ERROR'}, repr(e)) logger.error(f"Error: {e}") @@ -117,7 +117,7 @@ class SessionStartOperator(bpy.types.Operator): id=settings.username, address=settings.ip, port=settings.port, - ipc_port=settings.ttl_port + ipc_port=settings.ipc_port ) except Exception as e: self.report({'ERROR'}, repr(e)) diff --git a/multi_user/ui.py b/multi_user/ui.py index 5e7e1f0..9154039 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -121,30 +121,24 @@ class SESSION_PT_settings_network(bpy.types.Panel): row.prop(settings, "session_mode", expand=True) row = layout.row() + box = row.box() + + row = box.row() + row.prop(settings, "ip", text="IP") + row = box.row() + row.label(text="Port:") + row.prop(settings, "port", text="") + row = box.row() + row.label(text="IPC Port:") + row.prop(settings, "ipc_port", text="") + if settings.session_mode == 'HOST': - box = row.box() row = box.row() row.label(text="Start empty:") row.prop(settings, "start_empty", text="") row = box.row() - row.label(text="Port:") - row.prop(settings, "port", text="") - row = box.row() - row.label(text="IPC Port:") - row.prop(settings, "ttl_port", text="") - row = box.row() row.operator("session.start", text="HOST").host = True else: - box = row.box() - row = box.row() - row.prop(settings, "ip", text="IP") - row = box.row() - row.label(text="Port:") - row.prop(settings, "port", text="") - row = box.row() - row.label(text="IPC Port:") - row.prop(settings, "ttl_port", text="") - row = box.row() row.operator("session.start", text="CONNECT").host = False @@ -334,13 +328,12 @@ class SESSION_PT_services(bpy.types.Panel): settings = context.window_manager.session active_user = online_users[selected_user] if len(online_users)-1>=selected_user else 0 - # Create a simple row. - row = layout.row() for name, state in operators.client.services_state.items(): + row = layout.row() row.label(text=name) row.label(text=get_state_str(state)) - row = layout.row() + From 3d9a320612c1ab93131628a07c990af4ba6d2efe Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Wed, 19 Feb 2020 18:10:14 +0100 Subject: [PATCH 29/39] feat: update submodule version with service management layer --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 9e00109..abb2c04 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 9e0010993325f1d51fbf8f13b2b7053c002b48b3 +Subproject commit abb2c04e8f294ffdc548648d2c5288c64fc1e83d From e3d76c37dbb249b2f3e45a88755ab8af838e5de7 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 20 Feb 2020 11:57:37 +0100 Subject: [PATCH 30/39] feat: update submodule version --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index abb2c04..495a01d 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit abb2c04e8f294ffdc548648d2c5288c64fc1e83d +Subproject commit 495a01d0931bf7ffb29862679113b2ce9e47a782 From 699bdf5fe065ebaa8060600b7687c232ed8e872f Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 20 Feb 2020 13:17:28 +0100 Subject: [PATCH 31/39] feat: quitting state --- multi_user/libs/replication | 2 +- multi_user/ui.py | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 495a01d..4c104fa 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 495a01d0931bf7ffb29862679113b2ce9e47a782 +Subproject commit 4c104fa177a2ec1abbca2c1e907ba2af6581dd22 diff --git a/multi_user/ui.py b/multi_user/ui.py index 9154039..99d2df7 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -6,7 +6,7 @@ from .libs.replication.replication.constants import (ADDED, ERROR, FETCHED, STATE_ACTIVE, STATE_AUTH, STATE_CONFIG, STATE_SYNCING, STATE_INITIAL, STATE_SRV_SYNC, - STATE_WAITING) + STATE_WAITING, STATE_QUITTING) ICONS_PROP_STATES = ['TRIA_DOWN', # ADDED 'TRIA_UP', # COMMITED @@ -50,6 +50,8 @@ def get_state_str(state): state_str = 'PUSHING TO SERVER' elif state == STATE_INITIAL: state_str = 'INIT' + elif state == STATE_QUITTING: + state_str = 'QUITTING SESSION' return state_str class SESSION_PT_settings(bpy.types.Panel): @@ -79,15 +81,23 @@ class SESSION_PT_settings(bpy.types.Panel): row.label(text=f"Status : {get_state_str(cli_state['STATE'])}") row = layout.row() + current_state = cli_state['STATE'] + # STATE ACTIVE - if cli_state['STATE'] == STATE_ACTIVE: + if current_state == STATE_ACTIVE: row.operator("session.stop", icon='QUIT', text="Exit") row = layout.row() - # STATE SYNCING - else: - box = row.box() + # CONNECTION STATE + elif current_state in [ + STATE_SRV_SYNC, + STATE_SYNCING, + STATE_AUTH, + STATE_CONFIG, + STATE_WAITING]: + if cli_state['STATE'] in [STATE_SYNCING,STATE_SRV_SYNC,STATE_WAITING]: + box = row.box() box.label(text=printProgressBar( cli_state['CURRENT'], cli_state['TOTAL'], @@ -96,7 +106,10 @@ class SESSION_PT_settings(bpy.types.Panel): row = layout.row() row.operator("session.stop", icon='QUIT', text="CANCEL") - + elif current_state == STATE_QUITTING: + row = layout.row() + box = row.box() + box.label(text="waiting services to close...") class SESSION_PT_settings_network(bpy.types.Panel): bl_idname = "MULTIUSER_SETTINGS_NETWORK_PT_panel" From 67f1149f6592d5d24ed0fd6331e1c50cf35d01b7 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 20 Feb 2020 14:17:50 +0100 Subject: [PATCH 32/39] refactor: cleanup --- multi_user/libs/replication | 2 +- multi_user/operators.py | 1 - multi_user/ui.py | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 4c104fa..0f2ae75 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 4c104fa177a2ec1abbca2c1e907ba2af6581dd22 +Subproject commit 0f2ae759a710609031c24c251249d39a4d37173d diff --git a/multi_user/operators.py b/multi_user/operators.py index 948ab04..6840ae6 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -483,7 +483,6 @@ def depsgraph_evaluation(scene): session_infos = bpy.context.window_manager.session # NOTE: maybe we don't need to check each update but only the first - # thanks to our deps graph.... for update in reversed(dependency_updates): # Is the object tracked ? diff --git a/multi_user/ui.py b/multi_user/ui.py index 99d2df7..52bf106 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -329,6 +329,7 @@ class SESSION_PT_services(bpy.types.Panel): bl_region_type = 'UI' bl_category = "Multiuser" bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel' + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): From 56a625ae4815692be4b7fc23f4434f7e00e59b0f Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Thu, 20 Feb 2020 18:36:53 +0100 Subject: [PATCH 33/39] feat: quitting session progress bar --- multi_user/ui.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/multi_user/ui.py b/multi_user/ui.py index 52bf106..9513565 100644 --- a/multi_user/ui.py +++ b/multi_user/ui.py @@ -109,7 +109,19 @@ class SESSION_PT_settings(bpy.types.Panel): elif current_state == STATE_QUITTING: row = layout.row() box = row.box() - box.label(text="waiting services to close...") + + num_online_services = 0 + for name, state in operators.client.services_state.items(): + if state == STATE_ACTIVE: + num_online_services += 1 + + total_online_services = len(operators.client.services_state) + + box.label(text=printProgressBar( + total_online_services-num_online_services, + total_online_services, + length=16 + )) class SESSION_PT_settings_network(bpy.types.Panel): bl_idname = "MULTIUSER_SETTINGS_NETWORK_PT_panel" From 7d989faae6e63f13055761c1521328348b4f45bd Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 21 Feb 2020 12:00:34 +0100 Subject: [PATCH 34/39] feat: error handling during disconnection fix: various session disctonnect error (replication submodule) --- multi_user/libs/replication | 2 +- multi_user/operators.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 0f2ae75..90fdb44 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 0f2ae759a710609031c24c251249d39a4d37173d +Subproject commit 90fdb447f327ee9a02bcdd62adec6f89f6ab3749 diff --git a/multi_user/operators.py b/multi_user/operators.py index 6840ae6..077ff5d 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -159,23 +159,24 @@ class SessionStopOperator(bpy.types.Operator): def execute(self, context): global client, delayables, stop_modal_executor, server_process - - if server_process: - server_process.kill() - + assert(client) stop_modal_executor = True settings = context.window_manager.session settings.is_admin = False - assert(client) - - client.disconnect() for d in delayables: try: d.unregister() except: continue - presence.renderer.stop() + presence.renderer.stop() + + try: + client.disconnect() + except Exception as e: + self.report({'ERROR'}, repr(e)) + + client = None return {"FINISHED"} From 6142a092836f6a33737d6c0c53068813875f74e8 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 21 Feb 2020 13:08:24 +0100 Subject: [PATCH 35/39] fix: quit status --- multi_user/libs/replication | 2 +- multi_user/operators.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 90fdb44..3ec2ea8 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 90fdb447f327ee9a02bcdd62adec6f89f6ab3749 +Subproject commit 3ec2ea8b520d68cff37b91d810000f60e30f2f3f diff --git a/multi_user/operators.py b/multi_user/operators.py index 077ff5d..7bd4971 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -176,8 +176,6 @@ class SessionStopOperator(bpy.types.Operator): except Exception as e: self.report({'ERROR'}, repr(e)) - client = None - return {"FINISHED"} From 5d576d6f25cbaa74ecd48d068ce933965f76fdc6 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Fri, 21 Feb 2020 16:52:02 +0100 Subject: [PATCH 36/39] fix: modal operator error --- multi_user/bl_types/bl_datablock.py | 2 ++ multi_user/bl_types/bl_mesh.py | 1 - multi_user/libs/replication | 2 +- multi_user/operators.py | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/multi_user/bl_types/bl_datablock.py b/multi_user/bl_types/bl_datablock.py index a39558e..f54cbb4 100644 --- a/multi_user/bl_types/bl_datablock.py +++ b/multi_user/bl_types/bl_datablock.py @@ -80,6 +80,8 @@ class BlDatablock(ReplicatedDatablock): if self.pointer and hasattr(self.pointer, 'uuid'): self.pointer.uuid = self.uuid + + self.diff_method = DIFF_BINARY def library_apply(self): """Apply stored data diff --git a/multi_user/bl_types/bl_mesh.py b/multi_user/bl_types/bl_mesh.py index 97c5336..43667f6 100644 --- a/multi_user/bl_types/bl_mesh.py +++ b/multi_user/bl_types/bl_mesh.py @@ -87,7 +87,6 @@ class BlMesh(BlDatablock): bl_icon = 'MESH_DATA' def construct(self, data): - self.diff_method = DIFF_BINARY instance = bpy.data.meshes.new(data["name"]) instance.uuid = self.uuid return instance diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 3ec2ea8..19d018e 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 3ec2ea8b520d68cff37b91d810000f60e30f2f3f +Subproject commit 19d018e31b050a5a223f05910a7948645d9f0fdb diff --git a/multi_user/operators.py b/multi_user/operators.py index 7bd4971..72485ab 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -399,7 +399,7 @@ class ApplyArmatureOperator(bpy.types.Operator): if event.type == 'TIMER': global client - if client.state['STATE'] == STATE_ACTIVE: + if client and client.state['STATE'] == STATE_ACTIVE: nodes = client.list(filter=bl_types.bl_armature.BlArmature) for node in nodes: From 77979acc4213080b340fa2fac81a0bbb998e0b1f Mon Sep 17 00:00:00 2001 From: Swann Date: Sun, 23 Feb 2020 17:17:11 +0100 Subject: [PATCH 37/39] fix: Denied write access on connection for heavy scene (let blender delayables apply all data for us) --- multi_user/bl_types/bl_image.py | 2 +- multi_user/libs/replication | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/multi_user/bl_types/bl_image.py b/multi_user/bl_types/bl_image.py index 3439a3c..8949f45 100644 --- a/multi_user/bl_types/bl_image.py +++ b/multi_user/bl_types/bl_image.py @@ -30,7 +30,7 @@ class BlImage(BlDatablock): bl_id = "images" bl_class = bpy.types.Image bl_delay_refresh = 0 - bl_delay_apply = 0 + bl_delay_apply = 1 bl_automatic_push = False bl_icon = 'IMAGE_DATA' diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 19d018e..08d54ac 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 19d018e31b050a5a223f05910a7948645d9f0fdb +Subproject commit 08d54aceb8e0a1343a33ce04f9c51e05d2292306 From e71893c5b652165aa181639d39fd9b84cd86cd0c Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Mon, 24 Feb 2020 14:43:18 +0100 Subject: [PATCH 38/39] refactor: cleanup --- multi_user/libs/replication | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multi_user/libs/replication b/multi_user/libs/replication index 08d54ac..19b4eaf 160000 --- a/multi_user/libs/replication +++ b/multi_user/libs/replication @@ -1 +1 @@ -Subproject commit 08d54aceb8e0a1343a33ce04f9c51e05d2292306 +Subproject commit 19b4eafda23cdd073a18ab1998d556617c7b8a29 From d546bc257aeb361e6a4faed416e2f6380d2c63f7 Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Mon, 24 Feb 2020 15:49:11 +0100 Subject: [PATCH 39/39] feat: bones custom shapes --- multi_user/bl_types/bl_object.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/multi_user/bl_types/bl_object.py b/multi_user/bl_types/bl_object.py index 4ca7154..af17449 100644 --- a/multi_user/bl_types/bl_object.py +++ b/multi_user/bl_types/bl_object.py @@ -235,6 +235,9 @@ class BlObject(BlDatablock): 'rotation_mode', 'location', 'scale', + 'custom_shape', + 'use_custom_shape_bone_size', + 'custom_shape_scale', group_index, rotation ]