2019-02-08 00:41:18 +08:00
|
|
|
bl_info = {
|
2019-07-01 21:39:01 +08:00
|
|
|
"name": "Multi-User",
|
|
|
|
"author": "CUBE CREATIVE",
|
2019-05-21 22:53:55 +08:00
|
|
|
"description": "",
|
|
|
|
"blender": (2, 80, 0),
|
|
|
|
"location": "",
|
2019-09-18 23:54:02 +08:00
|
|
|
"warning": "Unstable addon, use it at your own risks",
|
2019-05-21 22:53:55 +08:00
|
|
|
"category": "Collaboration"
|
2019-02-08 00:41:18 +08:00
|
|
|
}
|
|
|
|
|
2019-03-14 23:44:18 +08:00
|
|
|
|
2019-07-02 00:04:35 +08:00
|
|
|
import logging
|
2019-08-23 18:28:57 +08:00
|
|
|
import os
|
2019-07-01 21:39:01 +08:00
|
|
|
import random
|
|
|
|
import sys
|
2019-08-23 18:28:57 +08:00
|
|
|
|
2019-07-01 21:39:01 +08:00
|
|
|
import bpy
|
2019-08-22 16:58:54 +08:00
|
|
|
from bpy.app.handlers import persistent
|
2019-07-01 21:39:01 +08:00
|
|
|
|
2019-09-25 00:37:36 +08:00
|
|
|
from . import environment, utils, presence
|
2019-09-24 20:42:59 +08:00
|
|
|
from .libs.replication.replication.constants import RP_COMMON
|
|
|
|
|
2019-08-23 18:28:57 +08:00
|
|
|
|
2019-09-18 23:54:02 +08:00
|
|
|
# TODO: remove dependency as soon as replication will be installed as a module
|
2019-07-01 21:39:01 +08:00
|
|
|
DEPENDENCIES = {
|
2019-08-27 05:14:30 +08:00
|
|
|
("zmq","zmq"),
|
2019-09-18 00:25:06 +08:00
|
|
|
("msgpack","msgpack"),
|
2019-08-27 06:50:38 +08:00
|
|
|
("yaml","pyyaml"),
|
|
|
|
("jsondiff","jsondiff")
|
2019-07-01 21:39:01 +08:00
|
|
|
}
|
2019-05-23 00:19:11 +08:00
|
|
|
|
2019-07-02 22:43:30 +08:00
|
|
|
|
2019-07-02 00:04:35 +08:00
|
|
|
logger = logging.getLogger(__name__)
|
2019-07-20 00:37:57 +08:00
|
|
|
logger.setLevel(logging.DEBUG)
|
2019-05-15 20:52:45 +08:00
|
|
|
|
2019-08-29 20:52:14 +08:00
|
|
|
#TODO: refactor config
|
2019-05-15 20:52:45 +08:00
|
|
|
# UTILITY FUNCTIONS
|
2019-08-29 00:58:18 +08:00
|
|
|
def generate_supported_types():
|
|
|
|
stype_dict = {'supported_types':{}}
|
|
|
|
for type in bl_types.types_to_register():
|
|
|
|
_type = getattr(bl_types, type)
|
|
|
|
props = {}
|
|
|
|
props['bl_delay_refresh']=_type.bl_delay_refresh
|
|
|
|
props['bl_delay_apply']=_type.bl_delay_apply
|
|
|
|
props['use_as_filter'] = False
|
|
|
|
props['icon'] = _type.bl_icon
|
2019-09-16 19:43:43 +08:00
|
|
|
props['auto_push']=_type.bl_automatic_push
|
2019-09-16 23:24:48 +08:00
|
|
|
props['bl_name']=_type.bl_id
|
2019-09-18 23:54:02 +08:00
|
|
|
|
2019-08-29 00:58:18 +08:00
|
|
|
stype_dict['supported_types'][_type.bl_rep_class.__name__] = props
|
|
|
|
|
|
|
|
return stype_dict
|
|
|
|
|
2019-09-18 23:54:02 +08:00
|
|
|
|
2019-05-15 20:52:45 +08:00
|
|
|
def client_list_callback(scene, context):
|
2019-08-14 21:57:07 +08:00
|
|
|
from . import operators
|
|
|
|
from .bl_types.bl_user import BlUser
|
2019-05-22 23:17:09 +08:00
|
|
|
|
2019-09-24 20:42:59 +08:00
|
|
|
items = [(RP_COMMON, RP_COMMON, "")]
|
2019-05-15 20:52:45 +08:00
|
|
|
|
2019-05-21 22:53:55 +08:00
|
|
|
username = bpy.context.window_manager.session.username
|
2019-08-14 21:57:07 +08:00
|
|
|
cli = operators.client
|
|
|
|
if cli:
|
|
|
|
client_keys = cli.list(filter=BlUser)
|
2019-06-14 00:09:16 +08:00
|
|
|
for k in client_keys:
|
2019-08-26 23:27:12 +08:00
|
|
|
name = cli.get(uuid=k).buffer["name"]
|
2019-05-21 22:53:55 +08:00
|
|
|
|
2019-07-11 21:45:56 +08:00
|
|
|
name_desc = name
|
2019-05-15 20:52:45 +08:00
|
|
|
if name == username:
|
2019-07-11 21:45:56 +08:00
|
|
|
name_desc += " (self)"
|
2019-05-15 20:52:45 +08:00
|
|
|
|
2019-07-11 21:45:56 +08:00
|
|
|
items.append((name, name_desc, ""))
|
2019-05-15 20:52:45 +08:00
|
|
|
|
|
|
|
return items
|
|
|
|
|
|
|
|
|
|
|
|
def randomColor():
|
|
|
|
r = random.random()
|
|
|
|
v = random.random()
|
|
|
|
b = random.random()
|
|
|
|
return [r, v, b]
|
|
|
|
|
2019-07-02 21:55:57 +08:00
|
|
|
class ReplicatedDatablock(bpy.types.PropertyGroup):
|
|
|
|
'''name = StringProperty() '''
|
2019-07-02 22:43:30 +08:00
|
|
|
type_name: bpy.props.StringProperty()
|
2019-09-16 23:24:48 +08:00
|
|
|
bl_name: bpy.props.StringProperty()
|
2019-08-29 00:58:18 +08:00
|
|
|
bl_delay_refresh: bpy.props.FloatProperty()
|
|
|
|
bl_delay_apply: bpy.props.FloatProperty()
|
2019-09-13 23:00:15 +08:00
|
|
|
use_as_filter: bpy.props.BoolProperty(default=True)
|
2019-09-16 19:43:43 +08:00
|
|
|
auto_push: bpy.props.BoolProperty(default=True)
|
2019-08-29 00:58:18 +08:00
|
|
|
icon: bpy.props.StringProperty()
|
2019-07-03 21:32:00 +08:00
|
|
|
|
2019-05-21 22:53:55 +08:00
|
|
|
class SessionProps(bpy.types.PropertyGroup):
|
2019-05-16 00:37:14 +08:00
|
|
|
username: bpy.props.StringProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="Username",
|
2019-09-24 19:26:51 +08:00
|
|
|
default="user_{}".format(utils.random_string_digits())
|
2019-05-21 22:53:55 +08:00
|
|
|
)
|
2019-05-16 00:37:14 +08:00
|
|
|
ip: bpy.props.StringProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="ip",
|
|
|
|
description='Distant host ip',
|
2019-09-24 19:26:51 +08:00
|
|
|
default="127.0.0.1"
|
2019-07-02 00:04:35 +08:00
|
|
|
)
|
2019-08-14 00:00:54 +08:00
|
|
|
user_uuid: bpy.props.StringProperty(
|
|
|
|
name="user_uuid",
|
|
|
|
default="None"
|
|
|
|
)
|
2019-05-16 00:37:14 +08:00
|
|
|
port: bpy.props.IntProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="port",
|
|
|
|
description='Distant host port',
|
2019-09-24 19:26:51 +08:00
|
|
|
default=5555
|
2019-07-02 00:04:35 +08:00
|
|
|
)
|
2019-05-16 00:37:14 +08:00
|
|
|
add_property_depth: bpy.props.IntProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="add_property_depth",
|
2019-07-02 00:04:35 +08:00
|
|
|
default=1
|
|
|
|
)
|
2019-08-09 16:58:47 +08:00
|
|
|
outliner_filter: bpy.props.StringProperty(name="None")
|
2019-09-24 19:26:51 +08:00
|
|
|
is_admin: bpy.props.BoolProperty(
|
|
|
|
name="is_admin",
|
|
|
|
default=False
|
|
|
|
)
|
|
|
|
init_scene: bpy.props.BoolProperty(
|
|
|
|
name="init_scene",
|
|
|
|
default=True
|
|
|
|
)
|
2019-07-02 00:14:48 +08:00
|
|
|
start_empty: bpy.props.BoolProperty(
|
|
|
|
name="start_empty",
|
2019-09-24 19:26:51 +08:00
|
|
|
default=True
|
|
|
|
)
|
2019-05-16 00:37:14 +08:00
|
|
|
active_object: bpy.props.PointerProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="active_object", type=bpy.types.Object)
|
2019-05-16 00:37:14 +08:00
|
|
|
session_mode: bpy.props.EnumProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name='session_mode',
|
|
|
|
description='session mode',
|
|
|
|
items={
|
|
|
|
('HOST', 'hosting', 'host a session'),
|
|
|
|
('CONNECT', 'connexion', 'connect to a session')},
|
|
|
|
default='HOST')
|
2019-09-25 00:37:36 +08:00
|
|
|
right_strategy: bpy.props.EnumProperty(
|
|
|
|
name='right_strategy',
|
|
|
|
description='right strategy',
|
|
|
|
items={
|
|
|
|
('STRICT', 'strict', 'strict right repartition'),
|
|
|
|
('COMMON', 'common', 'relaxed right repartition')},
|
|
|
|
default='COMMON')
|
2019-05-16 00:37:14 +08:00
|
|
|
client_color: bpy.props.FloatVectorProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="client_instance_color",
|
|
|
|
subtype='COLOR',
|
2019-09-24 19:26:51 +08:00
|
|
|
default=randomColor())
|
2019-05-16 00:37:14 +08:00
|
|
|
clients: bpy.props.EnumProperty(
|
2019-05-15 20:52:45 +08:00
|
|
|
name="clients",
|
|
|
|
description="client enum",
|
2019-08-09 16:58:47 +08:00
|
|
|
items=client_list_callback)
|
2019-07-02 00:04:35 +08:00
|
|
|
enable_presence: bpy.props.BoolProperty(
|
2019-09-19 19:02:39 +08:00
|
|
|
name="Presence overlay",
|
2019-05-15 20:52:45 +08:00
|
|
|
description='Enable overlay drawing module',
|
2019-09-24 20:42:59 +08:00
|
|
|
default=True,
|
|
|
|
update=presence.update_presence
|
|
|
|
)
|
|
|
|
presence_show_selected: bpy.props.BoolProperty(
|
|
|
|
name="Show selected objects",
|
|
|
|
description='Enable selection overlay ',
|
|
|
|
default=True,
|
|
|
|
update=presence.update_overlay_settings
|
2019-09-25 00:37:36 +08:00
|
|
|
)
|
2019-09-24 20:42:59 +08:00
|
|
|
presence_show_user: bpy.props.BoolProperty(
|
|
|
|
name="Show users",
|
|
|
|
description='Enable user overlay ',
|
|
|
|
default=True,
|
|
|
|
update=presence.update_overlay_settings
|
2019-07-02 00:04:35 +08:00
|
|
|
)
|
2019-07-02 21:55:57 +08:00
|
|
|
supported_datablock: bpy.props.CollectionProperty(
|
2019-07-02 23:44:59 +08:00
|
|
|
type=ReplicatedDatablock,
|
2019-07-02 21:55:57 +08:00
|
|
|
)
|
2019-08-29 00:58:18 +08:00
|
|
|
session_filter: bpy.props.CollectionProperty(
|
|
|
|
type=ReplicatedDatablock,
|
|
|
|
)
|
2019-09-19 05:10:36 +08:00
|
|
|
filter_owned: bpy.props.BoolProperty(
|
|
|
|
name="filter_owned",
|
|
|
|
description='Show only owned datablocks',
|
|
|
|
default=True
|
|
|
|
)
|
2019-09-19 19:02:39 +08:00
|
|
|
use_select_right: bpy.props.BoolProperty(
|
|
|
|
name="Selection right",
|
|
|
|
description='Change right on selection',
|
|
|
|
default=True
|
|
|
|
)
|
2019-07-02 00:04:35 +08:00
|
|
|
|
|
|
|
def load(self):
|
|
|
|
config = environment.load_config()
|
|
|
|
logger.info(config)
|
2019-08-29 00:58:18 +08:00
|
|
|
if "username" in config.keys():
|
2019-07-02 00:04:35 +08:00
|
|
|
self.username = config["username"]
|
|
|
|
self.ip = config["ip"]
|
|
|
|
self.port = config["port"]
|
|
|
|
self.start_empty = config["start_empty"]
|
|
|
|
self.enable_presence = config["enable_presence"]
|
2019-07-02 22:43:30 +08:00
|
|
|
self.client_color = config["client_color"]
|
2019-07-02 00:04:35 +08:00
|
|
|
else:
|
2019-07-02 21:55:57 +08:00
|
|
|
logger.error("Fail to read user config")
|
|
|
|
|
2019-07-02 22:43:30 +08:00
|
|
|
if len(self.supported_datablock)>0:
|
|
|
|
self.supported_datablock.clear()
|
2019-08-29 00:58:18 +08:00
|
|
|
if "supported_types" not in config:
|
|
|
|
config = generate_supported_types()
|
|
|
|
for datablock in config["supported_types"].keys():
|
2019-07-02 21:55:57 +08:00
|
|
|
rep_value = self.supported_datablock.add()
|
2019-07-03 21:03:37 +08:00
|
|
|
rep_value.name = datablock
|
2019-07-02 22:43:30 +08:00
|
|
|
rep_value.type_name = datablock
|
2019-09-24 19:26:51 +08:00
|
|
|
|
|
|
|
config_block = config["supported_types"][datablock]
|
|
|
|
rep_value.bl_delay_refresh = config_block['bl_delay_refresh']
|
|
|
|
rep_value.bl_delay_apply = config_block['bl_delay_apply']
|
|
|
|
rep_value.icon = config_block['icon']
|
|
|
|
rep_value.auto_push = config_block['auto_push']
|
|
|
|
rep_value.bl_name = config_block['bl_name']
|
2019-09-16 19:43:43 +08:00
|
|
|
|
2019-07-02 23:44:59 +08:00
|
|
|
def save(self,context):
|
|
|
|
config = environment.load_config()
|
|
|
|
|
|
|
|
config["username"] = self.username
|
|
|
|
config["ip"] = self.ip
|
|
|
|
config["port"] = self.port
|
|
|
|
config["start_empty"] = self.start_empty
|
|
|
|
config["enable_presence"] = self.enable_presence
|
|
|
|
config["client_color"] = [self.client_color.r,self.client_color.g,self.client_color.b]
|
2019-07-02 21:55:57 +08:00
|
|
|
|
2019-07-03 21:03:37 +08:00
|
|
|
|
2019-07-02 23:44:59 +08:00
|
|
|
for bloc in self.supported_datablock:
|
2019-09-24 19:26:51 +08:00
|
|
|
config_block = config["supported_types"][bloc.type_name]
|
|
|
|
config_block['bl_delay_refresh'] = bloc.bl_delay_refresh
|
|
|
|
config_block['bl_delay_apply'] = bloc.bl_delay_apply
|
|
|
|
config_block['use_as_filter'] = bloc.use_as_filter
|
|
|
|
config_block['icon'] = bloc.icon
|
|
|
|
config_block['auto_push'] = bloc.auto_push
|
|
|
|
config_block['bl_name'] = bloc.bl_name
|
2019-07-02 23:44:59 +08:00
|
|
|
environment.save_config(config)
|
2019-07-02 21:55:57 +08:00
|
|
|
|
2019-05-15 20:52:45 +08:00
|
|
|
|
2019-07-02 22:43:30 +08:00
|
|
|
classes = (
|
2019-07-02 21:55:57 +08:00
|
|
|
ReplicatedDatablock,
|
2019-08-08 21:35:43 +08:00
|
|
|
SessionProps,
|
2019-07-02 21:55:57 +08:00
|
|
|
|
2019-07-02 22:43:30 +08:00
|
|
|
)
|
2019-05-15 20:52:45 +08:00
|
|
|
|
2019-08-05 22:48:46 +08:00
|
|
|
libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication"
|
2019-05-21 22:53:55 +08:00
|
|
|
|
2019-07-09 04:39:11 +08:00
|
|
|
@persistent
|
|
|
|
def load_handler(dummy):
|
|
|
|
import bpy
|
|
|
|
bpy.context.window_manager.session.load()
|
|
|
|
|
2019-05-23 22:49:32 +08:00
|
|
|
def register():
|
2019-08-05 22:48:46 +08:00
|
|
|
if libs not in sys.path:
|
|
|
|
sys.path.append(libs)
|
|
|
|
|
2019-07-02 00:04:35 +08:00
|
|
|
environment.setup(DEPENDENCIES,bpy.app.binary_path_python)
|
2019-05-16 00:37:14 +08:00
|
|
|
|
|
|
|
from . import operators
|
|
|
|
from . import ui
|
|
|
|
|
2019-05-15 20:52:45 +08:00
|
|
|
for cls in classes:
|
|
|
|
bpy.utils.register_class(cls)
|
|
|
|
|
|
|
|
bpy.types.WindowManager.session = bpy.props.PointerProperty(
|
2019-05-21 22:53:55 +08:00
|
|
|
type=SessionProps)
|
2019-08-09 00:12:13 +08:00
|
|
|
bpy.types.ID.uuid = bpy.props.StringProperty(default="")
|
2019-09-24 19:26:51 +08:00
|
|
|
|
2019-07-02 00:04:35 +08:00
|
|
|
bpy.context.window_manager.session.load()
|
2019-09-24 19:26:51 +08:00
|
|
|
|
2019-04-10 23:01:21 +08:00
|
|
|
operators.register()
|
|
|
|
ui.register()
|
2019-08-29 20:52:14 +08:00
|
|
|
bpy.app.handlers.load_post.append(load_handler)
|
2019-02-08 00:41:18 +08:00
|
|
|
|
|
|
|
def unregister():
|
2019-05-16 00:37:14 +08:00
|
|
|
from . import operators
|
|
|
|
from . import ui
|
2019-05-21 22:53:55 +08:00
|
|
|
|
2019-04-10 23:01:21 +08:00
|
|
|
ui.unregister()
|
|
|
|
operators.unregister()
|
|
|
|
|
2019-05-15 20:52:45 +08:00
|
|
|
del bpy.types.WindowManager.session
|
|
|
|
|
2019-07-02 22:43:30 +08:00
|
|
|
for cls in reversed(classes):
|
2019-05-15 20:52:45 +08:00
|
|
|
bpy.utils.unregister_class(cls)
|