multi-user/multi_user/delayable.py

298 lines
11 KiB
Python
Raw Normal View History

import logging
2019-08-23 18:28:57 +08:00
2019-09-30 19:35:50 +08:00
import bpy
from . import operators, presence, utils
from .libs.replication.replication.constants import FETCHED, RP_COMMON, STATE_INITIAL,STATE_QUITTING, STATE_ACTIVE, STATE_SYNCING, STATE_SRV_SYNC
2019-08-23 18:28:57 +08:00
logger = logging.getLogger(__name__)
logger.setLevel(logging.WARNING)
class Delayable():
2019-08-14 21:01:30 +08:00
"""Delayable task interface
"""
2019-08-23 18:28:57 +08:00
def register(self):
raise NotImplementedError
def execute(self):
raise NotImplementedError
def unregister(self):
raise NotImplementedError
2019-08-23 18:28:57 +08:00
class Timer(Delayable):
"""Timer binder interface for blender
Run a bpy.app.Timer in the background looping at the given rate
"""
2019-08-23 18:28:57 +08:00
def __init__(self, duration=1):
self._timeout = duration
self._running = True
def register(self):
"""Register the timer into the blender timer system
"""
bpy.app.timers.register(self.main)
def main(self):
self.execute()
if self._running:
return self._timeout
def execute(self):
"""Main timer loop
"""
raise NotImplementedError
def unregister(self):
"""Unnegister the timer of the blender timer system
"""
if bpy.app.timers.is_registered(self.main):
bpy.app.timers.unregister(self.main)
self._running = False
2019-08-23 18:28:57 +08:00
2019-09-30 19:35:50 +08:00
class ApplyTimer(Timer):
2019-08-23 18:28:57 +08:00
def __init__(self, timout=1, target_type=None):
self._type = target_type
super().__init__(timout)
def execute(self):
client = operators.client
if client and client.state['STATE'] == STATE_ACTIVE:
nodes = client.list(filter=self._type)
for node in nodes:
node_ref = client.get(uuid=node)
if node_ref.state == FETCHED:
2019-10-04 00:30:46 +08:00
try:
client.apply(node)
2019-10-14 19:08:31 +08:00
except Exception as e:
logger.error(
"fail to apply {}: {}".format(node_ref.uuid, e))
class DynamicRightSelectTimer(Timer):
2019-10-02 20:01:45 +08:00
def __init__(self, timout=.1):
super().__init__(timout)
self._last_selection = []
self._user = None
self._right_strategy = RP_COMMON
def execute(self):
session = operators.client
settings = utils.get_preferences()
2020-02-08 00:56:58 +08:00
if session and session.state['STATE'] == STATE_ACTIVE:
# Find user
if self._user is None:
self._user = session.online_users.get(settings.username)
if self._right_strategy is None:
self._right_strategy = session.config[
'right_strategy']
if self._user:
current_selection = utils.get_selected_objects(
bpy.context.scene,
bpy.data.window_managers['WinMan'].windows[0].view_layer
)
if current_selection != self._last_selection:
if self._right_strategy == RP_COMMON:
obj_common = [
o for o in self._last_selection if o not in current_selection]
obj_ours = [
o for o in current_selection if o not in self._last_selection]
# change old selection right to common
for obj in obj_common:
node = session.get(uuid=obj)
if node and (node.owner == settings.username or node.owner == RP_COMMON):
recursive = True
if node.data and 'instance_type' in node.data.keys():
recursive = node.data['instance_type'] != 'COLLECTION'
session.change_owner(
node.uuid,
RP_COMMON,
recursive=recursive)
# change new selection to our
for obj in obj_ours:
node = session.get(uuid=obj)
if node and node.owner == RP_COMMON:
recursive = True
if node.data and 'instance_type' in node.data.keys():
recursive = node.data['instance_type'] != 'COLLECTION'
session.change_owner(
node.uuid,
settings.username,
recursive=recursive)
else:
return
2020-01-22 06:24:44 +08:00
self._last_selection = current_selection
2020-01-22 21:33:34 +08:00
user_metadata = {
'selected_objects': current_selection
}
session.update_user_metadata(user_metadata)
logger.info("Update selection")
2020-01-22 21:33:34 +08:00
# Fix deselection until right managment refactoring (with Roles concepts)
if len(current_selection) == 0 and self._right_strategy == RP_COMMON:
owned_keys = session.list(
2020-01-22 06:24:44 +08:00
filter_owner=settings.username)
for key in owned_keys:
node = session.get(uuid=key)
2020-01-22 21:33:34 +08:00
session.change_owner(
key,
RP_COMMON,
recursive=recursive)
2019-08-23 18:28:57 +08:00
for user, user_info in session.online_users.items():
if user != settings.username:
metadata = user_info.get('metadata')
if 'selected_objects' in metadata:
# Update selectionnable objects
for obj in bpy.data.objects:
if obj.hide_select and obj.uuid not in metadata['selected_objects']:
obj.hide_select = False
elif not obj.hide_select and obj.uuid in metadata['selected_objects']:
obj.hide_select = True
2019-10-14 19:08:31 +08:00
class Draw(Delayable):
def __init__(self):
self._handler = None
def register(self):
self._handler = bpy.types.SpaceView3D.draw_handler_add(
2019-08-23 18:28:57 +08:00
self.execute, (), 'WINDOW', 'POST_VIEW')
def execute(self):
raise NotImplementedError()
2019-08-23 18:28:57 +08:00
def unregister(self):
2019-08-14 03:32:15 +08:00
try:
bpy.types.SpaceView3D.draw_handler_remove(
2019-08-23 18:28:57 +08:00
self._handler, "WINDOW")
2019-08-14 03:32:15 +08:00
except:
2020-01-23 01:40:08 +08:00
pass
2019-08-23 18:28:57 +08:00
2019-10-02 20:01:45 +08:00
class DrawClient(Draw):
def execute(self):
2020-01-22 22:15:44 +08:00
session = getattr(operators, 'client', None)
renderer = getattr(presence, 'renderer', None)
2020-01-23 01:37:46 +08:00
2020-02-08 00:56:58 +08:00
if session and renderer and session.state['STATE'] == STATE_ACTIVE:
2019-10-02 20:01:45 +08:00
settings = bpy.context.window_manager.session
2020-01-22 06:24:44 +08:00
users = session.online_users
for user in users.values():
metadata = user.get('metadata')
color = metadata.get('color')
scene_current = metadata.get('scene_current')
user_showable = scene_current == bpy.context.scene.name or settings.presence_show_far_user
if color and scene_current and user_showable:
if settings.presence_show_selected and 'selected_objects' in metadata.keys():
renderer.draw_client_selection(
user['id'], color, metadata['selected_objects'])
if settings.presence_show_user and 'view_corners' in metadata:
renderer.draw_client_camera(
user['id'], metadata['view_corners'], color)
if not user_showable:
# TODO: remove this when user event drivent update will be
# ready
renderer.flush_selection()
renderer.flush_users()
2019-10-02 20:01:45 +08:00
2019-10-03 19:23:59 +08:00
class ClientUpdate(Timer):
2020-02-09 07:41:00 +08:00
def __init__(self, timout=.5):
2019-10-03 19:23:59 +08:00
super().__init__(timout)
self.handle_quit = False
def execute(self):
settings = utils.get_preferences()
2020-01-22 22:15:44 +08:00
session = getattr(operators, 'client', None)
renderer = getattr(presence, 'renderer', None)
2020-02-08 00:56:58 +08:00
if session and renderer and session.state['STATE'] == STATE_ACTIVE:
2020-01-23 01:37:46 +08:00
# Check if session has been closes prematurely
2020-02-08 00:56:58 +08:00
if session.state['STATE'] == 0:
2020-01-23 01:37:46 +08:00
bpy.ops.session.stop()
local_user = operators.client.online_users.get(
settings.username)
2020-01-22 21:33:34 +08:00
if not local_user:
return
local_user_metadata = local_user.get('metadata')
current_view_corners = presence.get_view_corners()
scene_current = bpy.context.scene.name
if not local_user_metadata or 'color' not in local_user_metadata.keys():
2020-01-22 21:33:34 +08:00
metadata = {
'view_corners': current_view_corners,
'view_matrix': presence.get_view_matrix(),
'color': (settings.client_color.r,
settings.client_color.g,
settings.client_color.b,
1),
'frame_current':bpy.context.scene.frame_current,
'scene_current': scene_current
2020-01-22 21:33:34 +08:00
}
session.update_user_metadata(metadata)
elif current_view_corners != local_user_metadata['view_corners']:
logger.info('update user metadata')
local_user_metadata['view_corners'] = current_view_corners
2020-01-22 22:15:44 +08:00
local_user_metadata['view_matrix'] = presence.get_view_matrix()
2020-01-22 21:33:34 +08:00
session.update_user_metadata(local_user_metadata)
elif scene_current != local_user_metadata['scene_current']:
local_user_metadata['scene_current'] = scene_current
session.update_user_metadata(local_user_metadata)
2020-01-22 06:24:44 +08:00
# sync online users
session_users = operators.client.online_users
ui_users = bpy.context.window_manager.online_users
for index, user in enumerate(ui_users):
if user.username not in session_users.keys():
ui_users.remove(index)
2020-01-22 22:15:44 +08:00
renderer.flush_selection()
renderer.flush_users()
break
for user in session_users:
if user not in ui_users:
new_key = ui_users.add()
new_key.name = user
2020-01-22 06:24:44 +08:00
new_key.username = user
2020-01-22 21:33:34 +08:00
# TODO: event drivent 3d view refresh
presence.refresh_3d_view()
elif session.state['STATE'] == STATE_QUITTING:
presence.refresh_3d_view()
self.handle_quit = True
elif session.state['STATE'] == STATE_INITIAL and self.handle_quit:
self.handle_quit = False
presence.refresh_3d_view()
operators.unregister_delayables()
presence.renderer.stop()
# # ui update
2020-03-20 21:17:58 +08:00
elif session.state['STATE'] != STATE_INITIAL:
2020-02-09 07:41:00 +08:00
presence.refresh_3d_view()