2020-03-20 21:56:50 +08:00
|
|
|
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
|
2019-08-28 18:57:09 +08:00
|
|
|
import logging
|
2020-12-22 23:04:50 +08:00
|
|
|
import sys
|
2021-03-11 22:45:48 +08:00
|
|
|
import traceback
|
2019-09-30 19:35:50 +08:00
|
|
|
import bpy
|
2020-12-22 23:04:50 +08:00
|
|
|
from replication.constants import (FETCHED, RP_COMMON, STATE_ACTIVE,
|
|
|
|
STATE_INITIAL, STATE_LOBBY, STATE_QUITTING,
|
|
|
|
STATE_SRV_SYNC, STATE_SYNCING, UP)
|
2021-01-12 02:54:57 +08:00
|
|
|
from replication.exception import NonAuthorizedOperationError, ContextError
|
2021-03-09 21:07:59 +08:00
|
|
|
from replication.interface import session
|
2021-05-17 17:12:18 +08:00
|
|
|
from replication import porcelain
|
2019-09-30 19:35:50 +08:00
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
from . import operators, utils
|
2021-06-24 22:01:14 +08:00
|
|
|
from .presence import (UserFrustumWidget, UserNameWidget, UserModeWidget, UserSelectionWidget,
|
2020-12-22 23:04:50 +08:00
|
|
|
generate_user_camera, get_view_matrix, refresh_3d_view,
|
|
|
|
refresh_sidebar_view, renderer)
|
2019-08-23 18:28:57 +08:00
|
|
|
|
2021-06-18 20:34:11 +08:00
|
|
|
from . import shared_data
|
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
this = sys.modules[__name__]
|
2020-10-06 04:34:43 +08:00
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
# Registered timers
|
|
|
|
this.registry = dict()
|
2020-12-09 21:49:26 +08:00
|
|
|
|
|
|
|
def is_annotating(context: bpy.types.Context):
|
2020-11-19 02:13:22 +08:00
|
|
|
""" Check if the annotate mode is enabled
|
|
|
|
"""
|
2020-12-09 21:49:26 +08:00
|
|
|
return bpy.context.workspace.tools.from_space_view3d_mode('OBJECT', create=False).idname == 'builtin.annotate'
|
|
|
|
|
2019-08-14 00:00:54 +08:00
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
class Timer(object):
|
2019-08-14 00:00:54 +08:00
|
|
|
"""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
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=10, id=None):
|
|
|
|
self._timeout = timeout
|
2020-12-10 01:34:56 +08:00
|
|
|
self.is_running = False
|
2020-12-22 23:04:50 +08:00
|
|
|
self.id = id if id else self.__class__.__name__
|
2019-08-14 00:00:54 +08:00
|
|
|
|
|
|
|
def register(self):
|
|
|
|
"""Register the timer into the blender timer system
|
|
|
|
"""
|
2020-10-06 04:34:43 +08:00
|
|
|
|
2020-12-10 01:34:56 +08:00
|
|
|
if not self.is_running:
|
2020-12-22 23:04:50 +08:00
|
|
|
this.registry[self.id] = self
|
2020-10-01 16:58:30 +08:00
|
|
|
bpy.app.timers.register(self.main)
|
2020-12-10 01:34:56 +08:00
|
|
|
self.is_running = True
|
2020-10-01 16:58:30 +08:00
|
|
|
logging.debug(f"Register {self.__class__.__name__}")
|
|
|
|
else:
|
2020-10-06 04:34:43 +08:00
|
|
|
logging.debug(
|
|
|
|
f"Timer {self.__class__.__name__} already registered")
|
2019-09-27 20:50:00 +08:00
|
|
|
|
|
|
|
def main(self):
|
2020-12-10 01:34:56 +08:00
|
|
|
try:
|
|
|
|
self.execute()
|
|
|
|
except Exception as e:
|
|
|
|
logging.error(e)
|
|
|
|
self.unregister()
|
2021-05-09 23:42:56 +08:00
|
|
|
traceback.print_exc()
|
2021-03-04 21:22:54 +08:00
|
|
|
session.disconnect(reason=f"Error during timer {self.id} execution")
|
2020-12-10 01:34:56 +08:00
|
|
|
else:
|
|
|
|
if self.is_running:
|
|
|
|
return self._timeout
|
2019-09-27 20:50:00 +08:00
|
|
|
|
2019-08-14 00:00:54 +08:00
|
|
|
def execute(self):
|
|
|
|
"""Main timer loop
|
|
|
|
"""
|
2019-09-27 20:50:00 +08:00
|
|
|
raise NotImplementedError
|
2019-08-14 00:00:54 +08:00
|
|
|
|
|
|
|
def unregister(self):
|
|
|
|
"""Unnegister the timer of the blender timer system
|
|
|
|
"""
|
2019-09-27 20:50:00 +08:00
|
|
|
if bpy.app.timers.is_registered(self.main):
|
2020-12-22 23:04:50 +08:00
|
|
|
logging.info(f"Unregistering {self.id}")
|
2019-09-27 20:50:00 +08:00
|
|
|
bpy.app.timers.unregister(self.main)
|
2021-06-18 20:34:11 +08:00
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
del this.registry[self.id]
|
2020-12-10 01:34:56 +08:00
|
|
|
self.is_running = False
|
2019-08-23 18:28:57 +08:00
|
|
|
|
2020-12-22 23:04:50 +08:00
|
|
|
class SessionBackupTimer(Timer):
|
|
|
|
def __init__(self, timeout=10, filepath=None):
|
2020-12-10 22:50:43 +08:00
|
|
|
self._filepath = filepath
|
2020-12-22 23:04:50 +08:00
|
|
|
super().__init__(timeout)
|
2020-12-10 22:50:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
def execute(self):
|
2021-06-02 15:35:55 +08:00
|
|
|
session.repository.dumps(self._filepath)
|
2019-09-30 19:35:50 +08:00
|
|
|
|
2021-03-04 21:22:54 +08:00
|
|
|
class SessionListenTimer(Timer):
|
|
|
|
def execute(self):
|
|
|
|
session.listen()
|
|
|
|
|
2019-08-14 00:00:54 +08:00
|
|
|
class ApplyTimer(Timer):
|
|
|
|
def execute(self):
|
2021-03-04 21:22:54 +08:00
|
|
|
if session and session.state == STATE_ACTIVE:
|
2021-06-04 20:02:09 +08:00
|
|
|
for node in session.repository.graph.keys():
|
|
|
|
node_ref = session.repository.graph.get(node)
|
2019-08-14 00:00:54 +08:00
|
|
|
|
|
|
|
if node_ref.state == FETCHED:
|
2019-10-04 00:30:46 +08:00
|
|
|
try:
|
2021-06-18 20:34:11 +08:00
|
|
|
shared_data.session.applied_updates.append(node)
|
2021-05-17 17:12:18 +08:00
|
|
|
porcelain.apply(session.repository, node)
|
2019-10-14 19:08:31 +08:00
|
|
|
except Exception as e:
|
2021-03-31 21:38:35 +08:00
|
|
|
logging.error(f"Fail to apply {node_ref.uuid}")
|
2021-03-11 22:45:48 +08:00
|
|
|
traceback.print_exc()
|
2020-12-09 21:49:26 +08:00
|
|
|
else:
|
2021-05-19 05:14:09 +08:00
|
|
|
impl = session.repository.rdp.get_implementation(node_ref.instance)
|
|
|
|
if impl.bl_reload_parent:
|
2021-06-04 20:02:09 +08:00
|
|
|
for parent in session.repository.graph.get_parents(node):
|
2021-02-12 17:49:04 +08:00
|
|
|
logging.debug("Refresh parent {node}")
|
2021-05-17 17:12:18 +08:00
|
|
|
porcelain.apply(session.repository,
|
2021-03-15 03:58:25 +08:00
|
|
|
parent.uuid,
|
|
|
|
force=True)
|
2021-06-22 17:36:51 +08:00
|
|
|
if hasattr(impl, 'bl_reload_child') and impl.bl_reload_child:
|
|
|
|
for dep in node_ref.dependencies:
|
|
|
|
porcelain.apply(session.repository,
|
|
|
|
dep,
|
|
|
|
force=True)
|
2019-08-14 00:00:54 +08:00
|
|
|
|
2021-01-13 22:49:07 +08:00
|
|
|
|
2019-09-19 05:55:30 +08:00
|
|
|
class DynamicRightSelectTimer(Timer):
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=.1):
|
|
|
|
super().__init__(timeout)
|
2019-11-23 01:32:39 +08:00
|
|
|
self._last_selection = []
|
|
|
|
self._user = None
|
2020-11-19 02:13:22 +08:00
|
|
|
self._annotating = False
|
2019-09-19 05:55:30 +08:00
|
|
|
|
|
|
|
def execute(self):
|
2020-03-02 18:09:45 +08:00
|
|
|
settings = utils.get_preferences()
|
2019-11-23 01:32:39 +08:00
|
|
|
|
2021-03-04 21:22:54 +08:00
|
|
|
if session and session.state == STATE_ACTIVE:
|
2019-11-23 01:32:39 +08:00
|
|
|
# Find user
|
|
|
|
if self._user is None:
|
2020-01-22 18:20:04 +08:00
|
|
|
self._user = session.online_users.get(settings.username)
|
2019-11-23 01:32:39 +08:00
|
|
|
|
|
|
|
if self._user:
|
2020-11-19 02:13:22 +08:00
|
|
|
ctx = bpy.context
|
2020-12-09 21:49:26 +08:00
|
|
|
annotation_gp = ctx.scene.grease_pencil
|
2020-11-19 02:13:22 +08:00
|
|
|
|
2021-01-13 21:24:16 +08:00
|
|
|
if annotation_gp and not annotation_gp.uuid:
|
|
|
|
ctx.scene.update_tag()
|
|
|
|
|
2020-11-19 02:13:22 +08:00
|
|
|
# if an annotation exist and is tracked
|
|
|
|
if annotation_gp and annotation_gp.uuid:
|
2021-06-04 20:02:09 +08:00
|
|
|
registered_gp = session.repository.graph.get(annotation_gp.uuid)
|
2020-12-09 21:49:26 +08:00
|
|
|
if is_annotating(bpy.context):
|
2020-11-19 02:13:22 +08:00
|
|
|
# try to get the right on it
|
|
|
|
if registered_gp.owner == RP_COMMON:
|
|
|
|
self._annotating = True
|
2020-12-09 21:49:26 +08:00
|
|
|
logging.debug(
|
|
|
|
"Getting the right on the annotation GP")
|
2021-06-02 17:31:23 +08:00
|
|
|
porcelain.lock(session.repository,
|
|
|
|
registered_gp.uuid,
|
|
|
|
ignore_warnings=True,
|
|
|
|
affect_dependencies=False)
|
2021-01-13 21:24:16 +08:00
|
|
|
|
|
|
|
if registered_gp.owner == settings.username:
|
2021-06-04 20:02:09 +08:00
|
|
|
gp_node = session.repository.graph.get(annotation_gp.uuid)
|
2021-05-21 23:29:22 +08:00
|
|
|
porcelain.commit(session.repository, gp_node.uuid)
|
|
|
|
porcelain.push(session.repository, 'origin', gp_node.uuid)
|
2021-01-13 21:24:16 +08:00
|
|
|
|
2020-12-09 21:49:26 +08:00
|
|
|
elif self._annotating:
|
2021-06-02 17:31:23 +08:00
|
|
|
porcelain.unlock(session.repository,
|
|
|
|
registered_gp.uuid,
|
|
|
|
ignore_warnings=True,
|
|
|
|
affect_dependencies=False)
|
2020-11-19 02:13:22 +08:00
|
|
|
|
2019-11-23 01:32:39 +08:00
|
|
|
current_selection = utils.get_selected_objects(
|
2020-02-25 23:35:26 +08:00
|
|
|
bpy.context.scene,
|
|
|
|
bpy.data.window_managers['WinMan'].windows[0].view_layer
|
|
|
|
)
|
2019-11-23 01:32:39 +08:00
|
|
|
if current_selection != self._last_selection:
|
2020-06-17 00:04:27 +08:00
|
|
|
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:
|
2021-06-04 20:02:09 +08:00
|
|
|
node = session.repository.graph.get(obj)
|
2020-06-17 00:04:27 +08:00
|
|
|
|
|
|
|
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'
|
2020-10-14 06:36:59 +08:00
|
|
|
try:
|
2021-06-02 17:31:23 +08:00
|
|
|
porcelain.unlock(session.repository,
|
|
|
|
node.uuid,
|
|
|
|
ignore_warnings=True,
|
|
|
|
affect_dependencies=recursive)
|
2020-10-14 06:36:59 +08:00
|
|
|
except NonAuthorizedOperationError:
|
2020-12-09 21:49:26 +08:00
|
|
|
logging.warning(
|
|
|
|
f"Not authorized to change {node} owner")
|
2020-06-17 00:04:27 +08:00
|
|
|
|
|
|
|
# change new selection to our
|
|
|
|
for obj in obj_ours:
|
2021-06-04 20:02:09 +08:00
|
|
|
node = session.repository.graph.get(obj)
|
2020-06-17 00:04:27 +08:00
|
|
|
|
|
|
|
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'
|
|
|
|
|
2020-10-14 06:36:59 +08:00
|
|
|
try:
|
2021-06-02 17:31:23 +08:00
|
|
|
porcelain.lock(session.repository,
|
|
|
|
node.uuid,
|
|
|
|
ignore_warnings=True,
|
|
|
|
affect_dependencies=recursive)
|
2020-10-14 06:36:59 +08:00
|
|
|
except NonAuthorizedOperationError:
|
2020-12-09 21:49:26 +08:00
|
|
|
logging.warning(
|
|
|
|
f"Not authorized to change {node} owner")
|
2020-06-17 00:04:27 +08:00
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
self._last_selection = current_selection
|
|
|
|
|
|
|
|
user_metadata = {
|
|
|
|
'selected_objects': current_selection
|
|
|
|
}
|
|
|
|
|
2021-06-02 18:59:53 +08:00
|
|
|
porcelain.update_user_metadata(session.repository, user_metadata)
|
2020-06-17 00:04:27 +08:00
|
|
|
logging.debug("Update selection")
|
|
|
|
|
|
|
|
# Fix deselection until right managment refactoring (with Roles concepts)
|
2020-12-10 01:34:56 +08:00
|
|
|
if len(current_selection) == 0 :
|
2021-06-04 20:02:09 +08:00
|
|
|
owned_keys = [k for k, v in session.repository.graph.items() if v.owner==settings.username]
|
2020-06-17 00:04:27 +08:00
|
|
|
for key in owned_keys:
|
2021-06-04 20:02:09 +08:00
|
|
|
node = session.repository.graph.get(key)
|
2020-10-14 06:36:59 +08:00
|
|
|
try:
|
2021-06-02 17:31:23 +08:00
|
|
|
porcelain.unlock(session.repository,
|
|
|
|
key,
|
|
|
|
ignore_warnings=True,
|
2021-06-03 21:03:09 +08:00
|
|
|
affect_dependencies=True)
|
2020-10-14 06:36:59 +08:00
|
|
|
except NonAuthorizedOperationError:
|
2020-12-09 21:49:26 +08:00
|
|
|
logging.warning(
|
|
|
|
f"Not authorized to change {key} owner")
|
2019-08-23 18:28:57 +08:00
|
|
|
|
2020-10-13 00:56:42 +08:00
|
|
|
for obj in bpy.data.objects:
|
|
|
|
object_uuid = getattr(obj, 'uuid', None)
|
|
|
|
if object_uuid:
|
2021-06-02 16:22:37 +08:00
|
|
|
is_selectable = not session.repository.is_node_readonly(object_uuid)
|
2020-10-13 00:56:42 +08:00
|
|
|
if obj.hide_select != is_selectable:
|
|
|
|
obj.hide_select = is_selectable
|
2021-06-18 20:34:11 +08:00
|
|
|
shared_data.session.applied_updates.append(object_uuid)
|
2019-10-14 19:08:31 +08:00
|
|
|
|
2020-12-09 21:49:26 +08:00
|
|
|
|
2019-10-03 19:23:59 +08:00
|
|
|
class ClientUpdate(Timer):
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=.1):
|
|
|
|
super().__init__(timeout)
|
2020-02-26 19:03:48 +08:00
|
|
|
self.handle_quit = False
|
2020-04-06 20:47:03 +08:00
|
|
|
self.users_metadata = {}
|
2019-08-14 00:00:54 +08:00
|
|
|
|
|
|
|
def execute(self):
|
2020-03-02 18:09:45 +08:00
|
|
|
settings = utils.get_preferences()
|
2020-01-23 01:37:46 +08:00
|
|
|
|
2020-06-16 23:15:32 +08:00
|
|
|
if session and renderer:
|
2021-03-04 21:22:54 +08:00
|
|
|
if session.state in [STATE_ACTIVE, STATE_LOBBY]:
|
2020-10-02 06:05:33 +08:00
|
|
|
local_user = session.online_users.get(
|
2020-09-18 04:47:11 +08:00
|
|
|
settings.username)
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-04-15 00:56:20 +08:00
|
|
|
if not local_user:
|
|
|
|
return
|
|
|
|
else:
|
2020-10-02 06:05:33 +08:00
|
|
|
for username, user_data in session.online_users.items():
|
2020-04-15 00:56:20 +08:00
|
|
|
if username != settings.username:
|
2020-09-18 04:47:11 +08:00
|
|
|
cached_user_data = self.users_metadata.get(
|
|
|
|
username)
|
2020-10-02 06:05:33 +08:00
|
|
|
new_user_data = session.online_users[username]['metadata']
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-04-15 00:56:20 +08:00
|
|
|
if cached_user_data is None:
|
|
|
|
self.users_metadata[username] = user_data['metadata']
|
|
|
|
elif 'view_matrix' in cached_user_data and 'view_matrix' in new_user_data and cached_user_data['view_matrix'] != new_user_data['view_matrix']:
|
2020-10-06 04:34:43 +08:00
|
|
|
refresh_3d_view()
|
2020-04-15 00:56:20 +08:00
|
|
|
self.users_metadata[username] = user_data['metadata']
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
self.users_metadata[username] = user_data['metadata']
|
|
|
|
|
|
|
|
local_user_metadata = local_user.get('metadata')
|
|
|
|
scene_current = bpy.context.scene.name
|
2020-09-18 04:47:11 +08:00
|
|
|
local_user = session.online_users.get(settings.username)
|
2020-10-06 04:34:43 +08:00
|
|
|
current_view_corners = generate_user_camera()
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-04-15 00:56:20 +08:00
|
|
|
# Init client metadata
|
|
|
|
if not local_user_metadata or 'color' not in local_user_metadata.keys():
|
|
|
|
metadata = {
|
2020-10-06 04:34:43 +08:00
|
|
|
'view_corners': get_view_matrix(),
|
|
|
|
'view_matrix': get_view_matrix(),
|
2020-04-15 00:56:20 +08:00
|
|
|
'color': (settings.client_color.r,
|
2020-09-18 04:47:11 +08:00
|
|
|
settings.client_color.g,
|
|
|
|
settings.client_color.b,
|
|
|
|
1),
|
2020-06-16 23:15:32 +08:00
|
|
|
'frame_current': bpy.context.scene.frame_current,
|
2021-06-24 22:01:14 +08:00
|
|
|
'scene_current': scene_current,
|
|
|
|
'mode_current': bpy.context.mode
|
2020-04-15 00:56:20 +08:00
|
|
|
}
|
2021-06-02 18:59:53 +08:00
|
|
|
porcelain.update_user_metadata(session.repository, metadata)
|
2020-04-15 00:56:20 +08:00
|
|
|
|
|
|
|
# Update client representation
|
|
|
|
# Update client current scene
|
|
|
|
elif scene_current != local_user_metadata['scene_current']:
|
|
|
|
local_user_metadata['scene_current'] = scene_current
|
2021-06-02 18:59:53 +08:00
|
|
|
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
2020-06-16 23:15:32 +08:00
|
|
|
elif 'view_corners' in local_user_metadata and current_view_corners != local_user_metadata['view_corners']:
|
2020-04-15 00:56:20 +08:00
|
|
|
local_user_metadata['view_corners'] = current_view_corners
|
2020-10-06 04:34:43 +08:00
|
|
|
local_user_metadata['view_matrix'] = get_view_matrix(
|
2020-09-18 04:47:11 +08:00
|
|
|
)
|
2021-06-02 18:59:53 +08:00
|
|
|
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
2021-06-24 22:01:14 +08:00
|
|
|
elif bpy.context.mode != local_user_metadata['mode_current']:
|
|
|
|
local_user_metadata['mode_current'] = bpy.context.mode
|
|
|
|
porcelain.update_user_metadata(session.repository, local_user_metadata)
|
2020-04-15 00:56:20 +08:00
|
|
|
|
2020-09-18 04:47:11 +08:00
|
|
|
|
2020-07-24 20:56:20 +08:00
|
|
|
class SessionStatusUpdate(Timer):
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=1):
|
|
|
|
super().__init__(timeout)
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-07-24 20:56:20 +08:00
|
|
|
def execute(self):
|
2020-10-06 04:34:43 +08:00
|
|
|
refresh_sidebar_view()
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-09-18 04:47:11 +08:00
|
|
|
|
2020-07-24 20:56:20 +08:00
|
|
|
class SessionUserSync(Timer):
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=1):
|
|
|
|
super().__init__(timeout)
|
2020-10-06 04:34:43 +08:00
|
|
|
self.settings = utils.get_preferences()
|
2020-06-16 23:15:32 +08:00
|
|
|
|
2020-07-17 22:33:39 +08:00
|
|
|
def execute(self):
|
2020-07-24 20:56:20 +08:00
|
|
|
if session and renderer:
|
|
|
|
# sync online users
|
2020-10-02 06:05:33 +08:00
|
|
|
session_users = session.online_users
|
2020-07-24 20:56:20 +08:00
|
|
|
ui_users = bpy.context.window_manager.online_users
|
|
|
|
|
|
|
|
for index, user in enumerate(ui_users):
|
2020-10-06 22:10:10 +08:00
|
|
|
if user.username not in session_users.keys() and \
|
|
|
|
user.username != self.settings.username:
|
|
|
|
renderer.remove_widget(f"{user.username}_cam")
|
|
|
|
renderer.remove_widget(f"{user.username}_select")
|
|
|
|
renderer.remove_widget(f"{user.username}_name")
|
2021-06-29 23:10:59 +08:00
|
|
|
renderer.remove_widget(f"{user.username}_mode")
|
2020-07-24 20:56:20 +08:00
|
|
|
ui_users.remove(index)
|
|
|
|
break
|
|
|
|
|
|
|
|
for user in session_users:
|
|
|
|
if user not in ui_users:
|
|
|
|
new_key = ui_users.add()
|
|
|
|
new_key.name = user
|
2020-09-18 04:47:11 +08:00
|
|
|
new_key.username = user
|
2021-06-24 22:01:14 +08:00
|
|
|
# if user != self.settings.username:
|
|
|
|
renderer.add_widget(
|
|
|
|
f"{user}_cam", UserFrustumWidget(user))
|
|
|
|
renderer.add_widget(
|
|
|
|
f"{user}_select", UserSelectionWidget(user))
|
|
|
|
renderer.add_widget(
|
|
|
|
f"{user}_name", UserNameWidget(user))
|
|
|
|
renderer.add_widget(
|
2021-06-29 23:10:59 +08:00
|
|
|
f"{user}_mode", UserModeWidget(user))
|
2020-10-01 16:58:30 +08:00
|
|
|
|
|
|
|
|
2020-10-02 18:11:53 +08:00
|
|
|
class MainThreadExecutor(Timer):
|
2020-12-22 23:04:50 +08:00
|
|
|
def __init__(self, timeout=1, execution_queue=None):
|
|
|
|
super().__init__(timeout)
|
2020-10-01 16:58:30 +08:00
|
|
|
self.execution_queue = execution_queue
|
2020-10-06 04:34:43 +08:00
|
|
|
|
2020-10-01 16:58:30 +08:00
|
|
|
def execute(self):
|
|
|
|
while not self.execution_queue.empty():
|
2020-11-26 18:37:51 +08:00
|
|
|
function, kwargs = self.execution_queue.get()
|
2020-10-01 16:58:30 +08:00
|
|
|
logging.debug(f"Executing {function.__name__}")
|
2020-12-22 23:04:50 +08:00
|
|
|
function(**kwargs)
|