diff --git a/multi_user/bl_types/bl_gpencil.py b/multi_user/bl_types/bl_gpencil.py index a2a81d5..530ab1b 100644 --- a/multi_user/bl_types/bl_gpencil.py +++ b/multi_user/bl_types/bl_gpencil.py @@ -28,7 +28,7 @@ from replication.protocol import ReplicatedDatablock from .bl_datablock import resolve_datablock_from_uuid from .bl_action import dump_animation_data, load_animation_data, resolve_animation_dependencies from ..utils import get_preferences - +from ..timers import is_annotating STROKE_POINT = [ 'co', @@ -65,36 +65,9 @@ def dump_stroke(stroke): :param stroke: target grease pencil stroke :type stroke: bpy.types.GPencilStroke - :return: dict + :return: (p_count, p_data) """ - - assert(stroke) - - dumper = Dumper() - dumper.include_filter = [ - "aspect", - "display_mode", - "draw_cyclic", - "end_cap_mode", - "hardeness", - "line_width", - "material_index", - "start_cap_mode", - "uv_rotation", - "uv_scale", - "uv_translation", - "vertex_color_fill", - ] - dumped_stroke = dumper.dump(stroke) - - # Stoke points - p_count = len(stroke.points) - dumped_stroke['p_count'] = p_count - dumped_stroke['points'] = np_dump_collection(stroke.points, STROKE_POINT) - - # TODO: uv_factor, uv_rotation - - return dumped_stroke + return (len(stroke.points), np_dump_collection(stroke.points, STROKE_POINT)) def load_stroke(stroke_data, stroke): @@ -107,12 +80,12 @@ def load_stroke(stroke_data, stroke): """ assert(stroke and stroke_data) - stroke.points.add(stroke_data["p_count"]) - np_load_collection(stroke_data['points'], stroke.points, STROKE_POINT) + stroke.points.add(stroke_data[0]) + np_load_collection(stroke_data[1], stroke.points, STROKE_POINT) # HACK: Temporary fix to trigger a BKE_gpencil_stroke_geometry_update to # fix fill issues - stroke.uv_scale = stroke_data["uv_scale"] + stroke.uv_scale = 1.0 def dump_frame(frame): @@ -147,10 +120,12 @@ def load_frame(frame_data, frame): assert(frame and frame_data) + # Load stroke points for stroke_data in frame_data['strokes_points']: target_stroke = frame.strokes.new() load_stroke(stroke_data, target_stroke) + # Load stroke metadata np_load_collection(frame_data['strokes'], frame.strokes, STROKE) @@ -170,7 +145,6 @@ def dump_layer(layer): 'opacity', 'channel_color', 'color', - # 'thickness', #TODO: enabling only for annotation 'tint_color', 'tint_factor', 'vertex_paint_opacity', @@ -323,7 +297,8 @@ class BlGpencil(ReplicatedDatablock): return bpy.context.mode == 'OBJECT' \ or layer_changed(datablock, data) \ or frame_changed(data) \ - or get_preferences().sync_flags.sync_during_editmode + or get_preferences().sync_flags.sync_during_editmode \ + or is_annotating(bpy.context) _type = bpy.types.GreasePencil _class = BlGpencil diff --git a/multi_user/bl_types/bl_scene.py b/multi_user/bl_types/bl_scene.py index cc02235..c5c9d00 100644 --- a/multi_user/bl_types/bl_scene.py +++ b/multi_user/bl_types/bl_scene.py @@ -403,8 +403,9 @@ class BlScene(ReplicatedDatablock): datablock.world = bpy.data.worlds[data['world']] # Annotation - if 'grease_pencil' in data.keys(): - datablock.grease_pencil = bpy.data.grease_pencils[data['grease_pencil']] + gpencil_uid = data.get('grease_pencil') + if gpencil_uid: + datablock.grease_pencil = resolve_datablock_from_uuid(gpencil_uid, bpy.data.grease_pencils) if get_preferences().sync_flags.sync_render_settings: if 'eevee' in data.keys(): @@ -470,7 +471,6 @@ class BlScene(ReplicatedDatablock): 'name', 'world', 'id', - 'grease_pencil', 'frame_start', 'frame_end', 'frame_step', @@ -530,6 +530,9 @@ class BlScene(ReplicatedDatablock): if datablock.timeline_markers: data['timeline_markers'] = [(m.name, m.frame, getattr(m.camera, 'uuid', None)) for m in datablock.timeline_markers] + if datablock.grease_pencil: + data['grease_pencil'] = datablock.grease_pencil.uuid + return data @staticmethod diff --git a/multi_user/operators.py b/multi_user/operators.py index 7279a0e..47b9778 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -285,6 +285,7 @@ class SessionStartOperator(bpy.types.Operator): deleyables.append(session_update) deleyables.append(session_user_sync) deleyables.append(session_listen) + deleyables.append(timers.AnnotationUpdates()) return {"FINISHED"} diff --git a/multi_user/timers.py b/multi_user/timers.py index 62d8a6d..0bfe1cf 100644 --- a/multi_user/timers.py +++ b/multi_user/timers.py @@ -41,7 +41,8 @@ this.registry = dict() def is_annotating(context: bpy.types.Context): """ Check if the annotate mode is enabled """ - return bpy.context.workspace.tools.from_space_view3d_mode('OBJECT', create=False).idname == 'builtin.annotate' + active_tool = bpy.context.workspace.tools.from_space_view3d_mode('OBJECT', create=False) + return (active_tool and active_tool.idname == 'builtin.annotate') class Timer(object): @@ -136,12 +137,50 @@ class ApplyTimer(Timer): force=True) +class AnnotationUpdates(Timer): + def __init__(self, timeout=1): + self._annotating = False + self._settings = utils.get_preferences() + + super().__init__(timeout) + + def execute(self): + if session and session.state == STATE_ACTIVE: + ctx = bpy.context + annotation_gp = ctx.scene.grease_pencil + + if annotation_gp and not annotation_gp.uuid: + ctx.scene.update_tag() + + # if an annotation exist and is tracked + if annotation_gp and annotation_gp.uuid: + registered_gp = session.repository.graph.get(annotation_gp.uuid) + if is_annotating(bpy.context): + # try to get the right on it + if registered_gp.owner == RP_COMMON: + self._annotating = True + logging.debug( + "Getting the right on the annotation GP") + porcelain.lock(session.repository, + registered_gp.uuid, + ignore_warnings=True, + affect_dependencies=False) + + if registered_gp.owner == self._settings.username: + porcelain.commit(session.repository, annotation_gp.uuid) + porcelain.push(session.repository, 'origin', annotation_gp.uuid) + + elif self._annotating: + porcelain.unlock(session.repository, + registered_gp.uuid, + ignore_warnings=True, + affect_dependencies=False) + class DynamicRightSelectTimer(Timer): def __init__(self, timeout=.1): super().__init__(timeout) self._last_selection = [] self._user = None - self._annotating = False def execute(self): settings = utils.get_preferences() @@ -152,37 +191,6 @@ class DynamicRightSelectTimer(Timer): self._user = session.online_users.get(settings.username) if self._user: - ctx = bpy.context - annotation_gp = ctx.scene.grease_pencil - - if annotation_gp and not annotation_gp.uuid: - ctx.scene.update_tag() - - # if an annotation exist and is tracked - if annotation_gp and annotation_gp.uuid: - registered_gp = session.repository.graph.get(annotation_gp.uuid) - if is_annotating(bpy.context): - # try to get the right on it - if registered_gp.owner == RP_COMMON: - self._annotating = True - logging.debug( - "Getting the right on the annotation GP") - porcelain.lock(session.repository, - registered_gp.uuid, - ignore_warnings=True, - affect_dependencies=False) - - if registered_gp.owner == settings.username: - gp_node = session.repository.graph.get(annotation_gp.uuid) - porcelain.commit(session.repository, gp_node.uuid) - porcelain.push(session.repository, 'origin', gp_node.uuid) - - elif self._annotating: - porcelain.unlock(session.repository, - registered_gp.uuid, - ignore_warnings=True, - affect_dependencies=False) - current_selection = utils.get_selected_objects( bpy.context.scene, bpy.data.window_managers['WinMan'].windows[0].view_layer