refactor: use client metadata
This commit is contained in:
@ -57,22 +57,19 @@ def generate_supported_types():
|
|||||||
|
|
||||||
def client_list_callback(scene, context):
|
def client_list_callback(scene, context):
|
||||||
from . import operators
|
from . import operators
|
||||||
from .bl_types.bl_user import BlUser
|
|
||||||
|
|
||||||
items = [(RP_COMMON, RP_COMMON, "")]
|
items = [(RP_COMMON, RP_COMMON, "")]
|
||||||
|
|
||||||
username = bpy.context.window_manager.session.username
|
username = bpy.context.window_manager.session.username
|
||||||
cli = operators.client
|
cli = operators.client
|
||||||
if cli:
|
if cli:
|
||||||
client_keys = cli.list(filter=BlUser)
|
client_ids = cli.online_users.keys()
|
||||||
for k in client_keys:
|
for id in client_ids:
|
||||||
name = cli.get(uuid=k).data["name"]
|
name_desc = id
|
||||||
|
if id == username:
|
||||||
name_desc = name
|
|
||||||
if name == username:
|
|
||||||
name_desc += " (self)"
|
name_desc += " (self)"
|
||||||
|
|
||||||
items.append((name, name_desc, ""))
|
items.append((id, name_desc, ""))
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
__all__ = [
|
__all__ = [
|
||||||
'bl_user',
|
|
||||||
'bl_object',
|
'bl_object',
|
||||||
'bl_mesh',
|
'bl_mesh',
|
||||||
'bl_camera',
|
'bl_camera',
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
import bpy
|
|
||||||
import mathutils
|
|
||||||
import jsondiff
|
|
||||||
|
|
||||||
from .. import utils
|
|
||||||
from .. import presence
|
|
||||||
from .bl_datablock import BlDatablock
|
|
||||||
from ..libs.replication.replication.constants import UP
|
|
||||||
|
|
||||||
|
|
||||||
class BlUser(BlDatablock):
|
|
||||||
bl_id = "users"
|
|
||||||
bl_class = presence.User
|
|
||||||
bl_delay_refresh = .1
|
|
||||||
bl_delay_apply = .1
|
|
||||||
bl_automatic_push = True
|
|
||||||
bl_icon = 'CON_ARMATURE'
|
|
||||||
|
|
||||||
def construct(self, data):
|
|
||||||
user = bpy.data.window_managers['WinMan'].online_users.add()
|
|
||||||
user.name = data['name']
|
|
||||||
user.username = data['name']
|
|
||||||
user.current_frame = data['current_frame']
|
|
||||||
|
|
||||||
def apply(self):
|
|
||||||
if self.pointer is None:
|
|
||||||
self.set_pointer()
|
|
||||||
|
|
||||||
self.load(self.data,self.pointer)
|
|
||||||
|
|
||||||
for obj in bpy.data.objects:
|
|
||||||
if obj.hide_select and obj.uuid not in self.data['selected_objects']:
|
|
||||||
obj.hide_select = False
|
|
||||||
elif not obj.hide_select and obj.uuid in self.data['selected_objects']:
|
|
||||||
obj.hide_select = True
|
|
||||||
|
|
||||||
presence.refresh_3d_view()
|
|
||||||
|
|
||||||
self.state = UP
|
|
||||||
|
|
||||||
def load(self, data, target):
|
|
||||||
target.current_frame = data['current_frame']
|
|
||||||
|
|
||||||
def dump(self, pointer=None):
|
|
||||||
data = utils.dump_anything.dump(pointer)
|
|
||||||
data['location'] = pointer.location
|
|
||||||
data['color'] = pointer.color
|
|
||||||
data['selected_objects'] = pointer.selected_objects
|
|
||||||
data['view_matrix'] = pointer.view_matrix
|
|
||||||
data['current_frame'] = bpy.context.scene.frame_current
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
self.pointer.is_dirty = True
|
|
||||||
|
|
||||||
def resolve(self):
|
|
||||||
self.pointer = bpy.data.window_managers['WinMan'].online_users.get(self.data['name'])
|
|
||||||
|
|
||||||
def is_valid(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,10 +3,10 @@ import logging
|
|||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from . import operators, presence, utils
|
from . import operators, presence, utils
|
||||||
from .bl_types.bl_user import BlUser
|
|
||||||
from .libs.replication.replication.constants import FETCHED, RP_COMMON
|
from .libs.replication.replication.constants import FETCHED, RP_COMMON
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
class Delayable():
|
class Delayable():
|
||||||
@ -83,7 +83,6 @@ class DynamicRightSelectTimer(Timer):
|
|||||||
super().__init__(timout)
|
super().__init__(timout)
|
||||||
self._last_selection = []
|
self._last_selection = []
|
||||||
self._user = None
|
self._user = None
|
||||||
self._user_metadata = None
|
|
||||||
self._right_strategy = RP_COMMON
|
self._right_strategy = RP_COMMON
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
@ -94,7 +93,6 @@ class DynamicRightSelectTimer(Timer):
|
|||||||
# Find user
|
# Find user
|
||||||
if self._user is None:
|
if self._user is None:
|
||||||
self._user = session.online_users.get(settings.username)
|
self._user = session.online_users.get(settings.username)
|
||||||
self._user_metadata = self._user.get('metadata')
|
|
||||||
|
|
||||||
if self._right_strategy is None:
|
if self._right_strategy is None:
|
||||||
self._right_strategy = session.get_config()[
|
self._right_strategy = session.get_config()[
|
||||||
@ -140,17 +138,21 @@ class DynamicRightSelectTimer(Timer):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self._last_selection = current_selection
|
self._last_selection = current_selection
|
||||||
self._user_metadata['selected_objects'] = current_selection
|
|
||||||
|
|
||||||
session.update_user_metadata(self._user_metadata)
|
user_metadata = {
|
||||||
|
'selected_objects': current_selection
|
||||||
|
}
|
||||||
|
|
||||||
|
session.update_user_metadata(user_metadata)
|
||||||
logger.info("Update selection")
|
logger.info("Update selection")
|
||||||
|
|
||||||
# Fix deselection until right managment refactoring (with Roles concepts)
|
# Fix deselection until right managment refactoring (with Roles concepts)
|
||||||
if len(current_selection) == 0 and self._right_strategy == RP_COMMON:
|
if len(current_selection) == 0 and self._right_strategy == RP_COMMON:
|
||||||
owned_keys = session.list(
|
owned_keys = session.list(
|
||||||
filter_owner=settings.username)
|
filter_owner=settings.username)
|
||||||
for key in owned_keys:
|
for key in owned_keys:
|
||||||
node = session.get(uuid=key)
|
node = session.get(uuid=key)
|
||||||
if not isinstance(node, BlUser):
|
|
||||||
session.change_owner(
|
session.change_owner(
|
||||||
key,
|
key,
|
||||||
RP_COMMON,
|
RP_COMMON,
|
||||||
@ -190,8 +192,9 @@ class Draw(Delayable):
|
|||||||
|
|
||||||
class DrawClient(Draw):
|
class DrawClient(Draw):
|
||||||
def execute(self):
|
def execute(self):
|
||||||
session = operators.client
|
session = getattr(operators, 'client')
|
||||||
if session and presence.renderer:
|
renderer = getattr(presence, 'renderer')
|
||||||
|
if session and renderer:
|
||||||
settings = bpy.context.window_manager.session
|
settings = bpy.context.window_manager.session
|
||||||
users = session.online_users
|
users = session.online_users
|
||||||
|
|
||||||
@ -199,10 +202,10 @@ class DrawClient(Draw):
|
|||||||
metadata = user.get('metadata')
|
metadata = user.get('metadata')
|
||||||
|
|
||||||
if settings.presence_show_selected and 'selected_objects' in metadata.keys():
|
if settings.presence_show_selected and 'selected_objects' in metadata.keys():
|
||||||
presence.renderer.draw_client_selection(
|
renderer.draw_client_selection(
|
||||||
user['id'], metadata['color'], metadata['selected_objects'])
|
user['id'], metadata['color'], metadata['selected_objects'])
|
||||||
if settings.presence_show_user and 'view_corners' in metadata:
|
if settings.presence_show_user and 'view_corners' in metadata:
|
||||||
presence.renderer.draw_client_camera(
|
renderer.draw_client_camera(
|
||||||
user['id'], metadata['view_corners'], metadata['color'])
|
user['id'], metadata['view_corners'], metadata['color'])
|
||||||
|
|
||||||
|
|
||||||
@ -213,23 +216,31 @@ class ClientUpdate(Timer):
|
|||||||
def execute(self):
|
def execute(self):
|
||||||
settings = bpy.context.window_manager.session
|
settings = bpy.context.window_manager.session
|
||||||
session_info = bpy.context.window_manager.session
|
session_info = bpy.context.window_manager.session
|
||||||
session = operators.client
|
session = getattr(operators, 'client')
|
||||||
if session:
|
if session:
|
||||||
local_user = operators.client.online_users.get(
|
local_user = operators.client.online_users.get(
|
||||||
session_info.username)
|
session_info.username)
|
||||||
|
if not local_user:
|
||||||
|
return
|
||||||
|
|
||||||
|
local_user_metadata = local_user.get('metadata')
|
||||||
|
current_view_corners = presence.get_view_corners()
|
||||||
|
|
||||||
|
if not local_user_metadata:
|
||||||
|
logger.info("init user metadata")
|
||||||
metadata = {
|
metadata = {
|
||||||
'view_corners': presence.get_view_corners(),
|
'view_corners': current_view_corners,
|
||||||
'view_matrix': presence.get_view_matrix(),
|
'view_matrix': presence.get_view_matrix(),
|
||||||
'color': (settings.client_color.r,
|
'color': (settings.client_color.r,
|
||||||
settings.client_color.g,
|
settings.client_color.g,
|
||||||
settings.client_color.b,
|
settings.client_color.b,
|
||||||
1),
|
1),
|
||||||
}
|
}
|
||||||
|
|
||||||
session.update_user_metadata(metadata)
|
session.update_user_metadata(metadata)
|
||||||
|
elif current_view_corners != local_user_metadata['view_corners']:
|
||||||
logger.info("{}".format(local_user))
|
logger.info('update user metadata')
|
||||||
|
local_user_metadata['view_corners'] = current_view_corners
|
||||||
|
session.update_user_metadata(local_user_metadata)
|
||||||
|
|
||||||
# sync online users
|
# sync online users
|
||||||
session_users = operators.client.online_users
|
session_users = operators.client.online_users
|
||||||
@ -240,7 +251,7 @@ class ClientUpdate(Timer):
|
|||||||
ui_users.remove(index)
|
ui_users.remove(index)
|
||||||
bpy.context.window_manager.session.presence_show_user = False
|
bpy.context.window_manager.session.presence_show_user = False
|
||||||
bpy.context.window_manager.session.presence_show_user = True
|
bpy.context.window_manager.session.presence_show_user = True
|
||||||
presence.refresh_3d_view()
|
|
||||||
break
|
break
|
||||||
|
|
||||||
for user in session_users:
|
for user in session_users:
|
||||||
@ -248,3 +259,6 @@ class ClientUpdate(Timer):
|
|||||||
new_key = ui_users.add()
|
new_key = ui_users.add()
|
||||||
new_key.name = user
|
new_key.name = user
|
||||||
new_key.username = user
|
new_key.username = user
|
||||||
|
|
||||||
|
# TODO: event drivent 3d view refresh
|
||||||
|
presence.refresh_3d_view()
|
||||||
|
Submodule multi_user/libs/replication updated: 20c122a522...d8537c31c0
@ -36,7 +36,6 @@ modal_executor_queue = None
|
|||||||
|
|
||||||
# OPERATORS
|
# OPERATORS
|
||||||
|
|
||||||
|
|
||||||
class SessionStartOperator(bpy.types.Operator):
|
class SessionStartOperator(bpy.types.Operator):
|
||||||
bl_idname = "session.start"
|
bl_idname = "session.start"
|
||||||
bl_label = "start"
|
bl_label = "start"
|
||||||
@ -54,16 +53,15 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
users = bpy.data.window_managers['WinMan'].online_users
|
users = bpy.data.window_managers['WinMan'].online_users
|
||||||
|
|
||||||
# TODO: Sync server clients
|
# TODO: Sync server clients
|
||||||
|
|
||||||
users.clear()
|
users.clear()
|
||||||
|
|
||||||
|
|
||||||
# save config
|
# save config
|
||||||
settings.save(context)
|
settings.save(context)
|
||||||
|
|
||||||
bpy_factory = ReplicatedDataFactory()
|
bpy_factory = ReplicatedDataFactory()
|
||||||
supported_bl_types = []
|
supported_bl_types = []
|
||||||
ui_context = context.copy()
|
ui_context = context.copy()
|
||||||
|
|
||||||
# init the factory with supported types
|
# init the factory with supported types
|
||||||
for type in bl_types.types_to_register():
|
for type in bl_types.types_to_register():
|
||||||
type_module = getattr(bl_types, type)
|
type_module = getattr(bl_types, type)
|
||||||
@ -88,6 +86,8 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
|
|
||||||
client = Session(factory=bpy_factory)
|
client = Session(factory=bpy_factory)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if self.host:
|
if self.host:
|
||||||
# Scene setup
|
# Scene setup
|
||||||
if settings.start_empty:
|
if settings.start_empty:
|
||||||
@ -118,18 +118,6 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
"A session is already hosted on this address")
|
"A session is already hosted on this address")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
# Init user settings
|
|
||||||
usr = presence.User(
|
|
||||||
username=settings.username,
|
|
||||||
color=(settings.client_color.r,
|
|
||||||
settings.client_color.g,
|
|
||||||
settings.client_color.b,
|
|
||||||
1),
|
|
||||||
)
|
|
||||||
|
|
||||||
settings.user_uuid = client.add(usr, owner=settings.username)
|
|
||||||
client.commit(settings.user_uuid)
|
|
||||||
|
|
||||||
if self.host:
|
if self.host:
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
scene_uuid = client.add(scene)
|
scene_uuid = client.add(scene)
|
||||||
|
@ -122,33 +122,6 @@ def get_view_matrix():
|
|||||||
|
|
||||||
return matrix_dumper.dump(rv3d.view_matrix)
|
return matrix_dumper.dump(rv3d.view_matrix)
|
||||||
|
|
||||||
class User():
|
|
||||||
def __init__(self, username=None, color=(0, 0, 0, 1)):
|
|
||||||
self.is_dirty = False
|
|
||||||
self.name = username
|
|
||||||
self.color = color
|
|
||||||
self.location = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
|
|
||||||
self.selected_objects = []
|
|
||||||
self.last_select_objects = []
|
|
||||||
self.view_matrix = None
|
|
||||||
|
|
||||||
def update_location(self):
|
|
||||||
current_coords = get_view_corners()
|
|
||||||
area, region, rv3d = view3d_find()
|
|
||||||
|
|
||||||
if area and region and rv3d:
|
|
||||||
current_coords = list(get_view_corners())
|
|
||||||
if current_coords and self.location != current_coords:
|
|
||||||
self.location = current_coords
|
|
||||||
|
|
||||||
matrix_dumper = utils.dump_anything.Dumper()
|
|
||||||
current_vm = matrix_dumper.dump(rv3d.view_matrix)
|
|
||||||
if self.view_matrix != current_vm:
|
|
||||||
self.view_matrix = current_vm
|
|
||||||
|
|
||||||
def update_selected_objects(self, context):
|
|
||||||
self.selected_objects = utils.get_selected_objects(context.scene)
|
|
||||||
|
|
||||||
def update_presence(self, context):
|
def update_presence(self, context):
|
||||||
global renderer
|
global renderer
|
||||||
|
|
||||||
@ -226,14 +199,14 @@ class DrawFactory(object):
|
|||||||
|
|
||||||
self.d2d_items.clear()
|
self.d2d_items.clear()
|
||||||
|
|
||||||
def draw_client_selection(self, client_uuid, client_color, client_selection):
|
def draw_client_selection(self, client_id, client_color, client_selection):
|
||||||
local_user = bpy.context.window_manager.session.user_uuid
|
local_user = bpy.context.window_manager.session.username
|
||||||
|
|
||||||
if local_user != client_uuid:
|
if local_user != client_id:
|
||||||
self.flush_selection(client_uuid)
|
self.flush_selection(client_id)
|
||||||
|
|
||||||
for select_ob in client_selection:
|
for select_ob in client_selection:
|
||||||
drawable_key = "{}_select_{}".format(client_uuid, select_ob)
|
drawable_key = "{}_select_{}".format(client_id, select_ob)
|
||||||
|
|
||||||
ob = utils.find_from_attr("uuid", select_ob, bpy.data.objects)
|
ob = utils.find_from_attr("uuid", select_ob, bpy.data.objects)
|
||||||
if not ob:
|
if not ob:
|
||||||
@ -282,11 +255,11 @@ class DrawFactory(object):
|
|||||||
|
|
||||||
self.d3d_items[key] = (shader, batch, color)
|
self.d3d_items[key] = (shader, batch, color)
|
||||||
|
|
||||||
def draw_client_camera(self, client_uuid, client_location, client_color):
|
def draw_client_camera(self, client_id, client_location, client_color):
|
||||||
if client_location:
|
if client_location:
|
||||||
local_user = bpy.context.window_manager.session.user_uuid
|
local_user = bpy.context.window_manager.session.username
|
||||||
|
|
||||||
if local_user != client_uuid:
|
if local_user != client_id:
|
||||||
try:
|
try:
|
||||||
indices = (
|
indices = (
|
||||||
(1, 3), (2, 1), (3, 0),
|
(1, 3), (2, 1), (3, 0),
|
||||||
@ -301,8 +274,8 @@ class DrawFactory(object):
|
|||||||
batch = batch_for_shader(
|
batch = batch_for_shader(
|
||||||
shader, 'LINES', {"pos": position}, indices=indices)
|
shader, 'LINES', {"pos": position}, indices=indices)
|
||||||
|
|
||||||
self.d3d_items[client_uuid] = (shader, batch, color)
|
self.d3d_items[client_id] = (shader, batch, color)
|
||||||
self.d2d_items[client_uuid] = (position[1], client_uuid, color)
|
self.d2d_items[client_id] = (position[1], client_id, color)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Draw client exception {}".format(e))
|
logger.error("Draw client exception {}".format(e))
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from . import operators
|
from . import operators
|
||||||
from .bl_types.bl_user import BlUser
|
|
||||||
from .libs.replication.replication.constants import (ADDED, ERROR, FETCHED,
|
from .libs.replication.replication.constants import (ADDED, ERROR, FETCHED,
|
||||||
MODIFIED, RP_COMMON, UP)
|
MODIFIED, RP_COMMON, UP)
|
||||||
|
|
||||||
@ -188,7 +187,7 @@ class SESSION_PT_user(bpy.types.Panel):
|
|||||||
# Create a simple row.
|
# Create a simple row.
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
box = row.box()
|
box = row.box()
|
||||||
split = box.split(factor=0.3)
|
split = box.split(factor=0.5)
|
||||||
split.label(text="user")
|
split.label(text="user")
|
||||||
split.label(text="frame")
|
split.label(text="frame")
|
||||||
split.label(text="ping")
|
split.label(text="ping")
|
||||||
@ -219,7 +218,7 @@ class SESSION_UL_users(bpy.types.UIList):
|
|||||||
ping = str(user_stat['latency'])
|
ping = str(user_stat['latency'])
|
||||||
break
|
break
|
||||||
|
|
||||||
split = layout.split(factor=0.3)
|
split = layout.split(factor=0.5)
|
||||||
split.label(text=item.username)
|
split.label(text=item.username)
|
||||||
split.label(text=str(item.current_frame))
|
split.label(text=str(item.current_frame))
|
||||||
split.label(text=ping)
|
split.label(text=ping)
|
||||||
@ -256,7 +255,7 @@ def draw_property(context, parent, property_uuid, level=0):
|
|||||||
settings = context.window_manager.session
|
settings = context.window_manager.session
|
||||||
item = operators.client.get(uuid=property_uuid)
|
item = operators.client.get(uuid=property_uuid)
|
||||||
|
|
||||||
if item.str_type == 'BlUser' or item.state == ERROR:
|
if item.state == ERROR:
|
||||||
return
|
return
|
||||||
|
|
||||||
area_msg = parent.row(align=True)
|
area_msg = parent.row(align=True)
|
||||||
|
@ -27,6 +27,7 @@ def has_driver(target):
|
|||||||
and target.animation_data
|
and target.animation_data
|
||||||
and target.animation_data.drivers)
|
and target.animation_data.drivers)
|
||||||
|
|
||||||
|
|
||||||
def find_from_attr(attr_name, attr_value, list):
|
def find_from_attr(attr_name, attr_value, list):
|
||||||
for item in list:
|
for item in list:
|
||||||
if getattr(item, attr_name, None) == attr_value:
|
if getattr(item, attr_name, None) == attr_value:
|
||||||
@ -56,7 +57,7 @@ def get_datablock_users(datablock):
|
|||||||
def random_string_digits(stringLength=6):
|
def random_string_digits(stringLength=6):
|
||||||
"""Generate a random string of letters and digits """
|
"""Generate a random string of letters and digits """
|
||||||
lettersAndDigits = string.ascii_letters + string.digits
|
lettersAndDigits = string.ascii_letters + string.digits
|
||||||
return ''.join(random.choice(lettersAndDigits) for i in range(stringLength))
|
return ''.join(random.choices(lettersAndDigits, k=stringLength))
|
||||||
|
|
||||||
|
|
||||||
def clean_scene():
|
def clean_scene():
|
||||||
@ -151,6 +152,7 @@ def dump_datablock_attibutes(datablock=None, attributes=[], depth=1, dickt=None)
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def resolve_from_id(id, optionnal_type=None):
|
def resolve_from_id(id, optionnal_type=None):
|
||||||
for category in dir(bpy.data):
|
for category in dir(bpy.data):
|
||||||
root = getattr(bpy.data, category)
|
root = getattr(bpy.data, category)
|
||||||
|
Reference in New Issue
Block a user