feat: store addon config in user preference (except runtime vars)
Related to #20
This commit is contained in:
@ -21,7 +21,7 @@ import sys
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.app.handlers import persistent
|
from bpy.app.handlers import persistent
|
||||||
|
|
||||||
from . import environment, utils, presence
|
from . import environment, utils, presence, preferences
|
||||||
from .libs.replication.replication.constants import RP_COMMON
|
from .libs.replication.replication.constants import RP_COMMON
|
||||||
|
|
||||||
|
|
||||||
@ -37,34 +37,12 @@ DEPENDENCIES = {
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.WARNING)
|
logger.setLevel(logging.WARNING)
|
||||||
|
|
||||||
#TODO: refactor config
|
|
||||||
# UTILITY FUNCTIONS
|
|
||||||
def generate_supported_types():
|
|
||||||
stype_dict = {'supported_types':{}}
|
|
||||||
for type in bl_types.types_to_register():
|
|
||||||
type_module = getattr(bl_types, type)
|
|
||||||
type_impl_name = "Bl{}".format(type.split('_')[1].capitalize())
|
|
||||||
type_module_class = getattr(type_module, type_impl_name)
|
|
||||||
|
|
||||||
props = {}
|
|
||||||
props['bl_delay_refresh']=type_module_class.bl_delay_refresh
|
|
||||||
props['bl_delay_apply']=type_module_class.bl_delay_apply
|
|
||||||
props['use_as_filter'] = False
|
|
||||||
props['icon'] = type_module_class.bl_icon
|
|
||||||
props['auto_push']=type_module_class.bl_automatic_push
|
|
||||||
props['bl_name']=type_module_class.bl_id
|
|
||||||
|
|
||||||
stype_dict['supported_types'][type_impl_name] = props
|
|
||||||
|
|
||||||
return stype_dict
|
|
||||||
|
|
||||||
|
|
||||||
def client_list_callback(scene, context):
|
def client_list_callback(scene, context):
|
||||||
from . import operators
|
from . import operators
|
||||||
|
|
||||||
items = [(RP_COMMON, RP_COMMON, "")]
|
items = [(RP_COMMON, RP_COMMON, "")]
|
||||||
|
|
||||||
username = bpy.context.window_manager.session.username
|
username = bpy.context.preferences.addons[__package__].preferences.username
|
||||||
cli = operators.client
|
cli = operators.client
|
||||||
if cli:
|
if cli:
|
||||||
client_ids = cli.online_users.keys()
|
client_ids = cli.online_users.keys()
|
||||||
@ -77,23 +55,6 @@ def client_list_callback(scene, context):
|
|||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def randomColor():
|
|
||||||
r = random.random()
|
|
||||||
v = random.random()
|
|
||||||
b = random.random()
|
|
||||||
return [r, v, b]
|
|
||||||
|
|
||||||
class ReplicatedDatablock(bpy.types.PropertyGroup):
|
|
||||||
'''name = StringProperty() '''
|
|
||||||
type_name: bpy.props.StringProperty()
|
|
||||||
bl_name: bpy.props.StringProperty()
|
|
||||||
bl_delay_refresh: bpy.props.FloatProperty()
|
|
||||||
bl_delay_apply: bpy.props.FloatProperty()
|
|
||||||
use_as_filter: bpy.props.BoolProperty(default=True)
|
|
||||||
auto_push: bpy.props.BoolProperty(default=True)
|
|
||||||
icon: bpy.props.StringProperty()
|
|
||||||
|
|
||||||
class SessionUser(bpy.types.PropertyGroup):
|
class SessionUser(bpy.types.PropertyGroup):
|
||||||
"""Session User
|
"""Session User
|
||||||
|
|
||||||
@ -104,37 +65,10 @@ class SessionUser(bpy.types.PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
class SessionProps(bpy.types.PropertyGroup):
|
class SessionProps(bpy.types.PropertyGroup):
|
||||||
username: bpy.props.StringProperty(
|
|
||||||
name="Username",
|
|
||||||
default="user_{}".format(utils.random_string_digits())
|
|
||||||
)
|
|
||||||
ip: bpy.props.StringProperty(
|
|
||||||
name="ip",
|
|
||||||
description='Distant host ip',
|
|
||||||
default="127.0.0.1"
|
|
||||||
)
|
|
||||||
user_uuid: bpy.props.StringProperty(
|
|
||||||
name="user_uuid",
|
|
||||||
default="None"
|
|
||||||
)
|
|
||||||
port: bpy.props.IntProperty(
|
|
||||||
name="port",
|
|
||||||
description='Distant host port',
|
|
||||||
default=5555
|
|
||||||
)
|
|
||||||
ipc_port: bpy.props.IntProperty(
|
|
||||||
name="ipc_port",
|
|
||||||
description='internal ttl port(only usefull for multiple local instances)',
|
|
||||||
default=5561
|
|
||||||
)
|
|
||||||
is_admin: bpy.props.BoolProperty(
|
is_admin: bpy.props.BoolProperty(
|
||||||
name="is_admin",
|
name="is_admin",
|
||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
start_empty: bpy.props.BoolProperty(
|
|
||||||
name="start_empty",
|
|
||||||
default=True
|
|
||||||
)
|
|
||||||
session_mode: bpy.props.EnumProperty(
|
session_mode: bpy.props.EnumProperty(
|
||||||
name='session_mode',
|
name='session_mode',
|
||||||
description='session mode',
|
description='session mode',
|
||||||
@ -142,17 +76,6 @@ class SessionProps(bpy.types.PropertyGroup):
|
|||||||
('HOST', 'hosting', 'host a session'),
|
('HOST', 'hosting', 'host a session'),
|
||||||
('CONNECT', 'connexion', 'connect to a session')},
|
('CONNECT', 'connexion', 'connect to a session')},
|
||||||
default='HOST')
|
default='HOST')
|
||||||
right_strategy: bpy.props.EnumProperty(
|
|
||||||
name='right_strategy',
|
|
||||||
description='right strategy',
|
|
||||||
items={
|
|
||||||
('STRICT', 'strict', 'strict right repartition'),
|
|
||||||
('COMMON', 'common', 'relaxed right repartition')},
|
|
||||||
default='COMMON')
|
|
||||||
client_color: bpy.props.FloatVectorProperty(
|
|
||||||
name="client_instance_color",
|
|
||||||
subtype='COLOR',
|
|
||||||
default=randomColor())
|
|
||||||
clients: bpy.props.EnumProperty(
|
clients: bpy.props.EnumProperty(
|
||||||
name="clients",
|
name="clients",
|
||||||
description="client enum",
|
description="client enum",
|
||||||
@ -175,12 +98,6 @@ class SessionProps(bpy.types.PropertyGroup):
|
|||||||
default=True,
|
default=True,
|
||||||
update=presence.update_overlay_settings
|
update=presence.update_overlay_settings
|
||||||
)
|
)
|
||||||
supported_datablock: bpy.props.CollectionProperty(
|
|
||||||
type=ReplicatedDatablock,
|
|
||||||
)
|
|
||||||
session_filter: bpy.props.CollectionProperty(
|
|
||||||
type=ReplicatedDatablock,
|
|
||||||
)
|
|
||||||
filter_owned: bpy.props.BoolProperty(
|
filter_owned: bpy.props.BoolProperty(
|
||||||
name="filter_owned",
|
name="filter_owned",
|
||||||
description='Show only owned datablocks',
|
description='Show only owned datablocks',
|
||||||
@ -193,73 +110,13 @@ class SessionProps(bpy.types.PropertyGroup):
|
|||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def load(self):
|
|
||||||
config = environment.load_config()
|
|
||||||
if "username" in config.keys():
|
|
||||||
self.username = config["username"]
|
|
||||||
self.ip = config["ip"]
|
|
||||||
self.port = config["port"]
|
|
||||||
self.start_empty = config["start_empty"]
|
|
||||||
self.enable_presence = config["enable_presence"]
|
|
||||||
self.client_color = config["client_color"]
|
|
||||||
else:
|
|
||||||
logger.error("Fail to read user config")
|
|
||||||
|
|
||||||
if len(self.supported_datablock)>0:
|
|
||||||
self.supported_datablock.clear()
|
|
||||||
if "supported_types" not in config:
|
|
||||||
config = generate_supported_types()
|
|
||||||
for datablock in config["supported_types"].keys():
|
|
||||||
rep_value = self.supported_datablock.add()
|
|
||||||
rep_value.name = datablock
|
|
||||||
rep_value.type_name = datablock
|
|
||||||
|
|
||||||
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']
|
|
||||||
|
|
||||||
def save(self,context):
|
|
||||||
config = environment.load_config()
|
|
||||||
|
|
||||||
if "supported_types" not in config:
|
|
||||||
config = generate_supported_types()
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
|
|
||||||
for bloc in self.supported_datablock:
|
|
||||||
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
|
|
||||||
environment.save_config(config)
|
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
SessionUser,
|
SessionUser,
|
||||||
ReplicatedDatablock,
|
|
||||||
SessionProps,
|
SessionProps,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication\\replication"
|
libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication\\replication"
|
||||||
|
|
||||||
@persistent
|
|
||||||
def load_handler(dummy):
|
|
||||||
import bpy
|
|
||||||
bpy.context.window_manager.session.load()
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
if libs not in sys.path:
|
if libs not in sys.path:
|
||||||
sys.path.append(libs)
|
sys.path.append(libs)
|
||||||
@ -269,6 +126,7 @@ def register():
|
|||||||
from . import presence
|
from . import presence
|
||||||
from . import operators
|
from . import operators
|
||||||
from . import ui
|
from . import ui
|
||||||
|
from . import preferences
|
||||||
|
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
@ -280,22 +138,22 @@ def register():
|
|||||||
type=SessionUser
|
type=SessionUser
|
||||||
)
|
)
|
||||||
bpy.types.WindowManager.user_index = bpy.props.IntProperty()
|
bpy.types.WindowManager.user_index = bpy.props.IntProperty()
|
||||||
bpy.context.window_manager.session.load()
|
|
||||||
|
|
||||||
|
preferences.register()
|
||||||
presence.register()
|
presence.register()
|
||||||
operators.register()
|
operators.register()
|
||||||
ui.register()
|
ui.register()
|
||||||
bpy.app.handlers.load_post.append(load_handler)
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
from . import presence
|
from . import presence
|
||||||
from . import operators
|
from . import operators
|
||||||
from . import ui
|
from . import ui
|
||||||
|
from . import preferences
|
||||||
|
|
||||||
presence.unregister()
|
presence.unregister()
|
||||||
ui.unregister()
|
ui.unregister()
|
||||||
operators.unregister()
|
operators.unregister()
|
||||||
|
preferences.unregister()
|
||||||
del bpy.types.WindowManager.session
|
del bpy.types.WindowManager.session
|
||||||
|
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
|
@ -88,7 +88,7 @@ class DynamicRightSelectTimer(Timer):
|
|||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
session = operators.client
|
session = operators.client
|
||||||
settings = bpy.context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
if session and session.state['STATE'] == STATE_ACTIVE:
|
if session and session.state['STATE'] == STATE_ACTIVE:
|
||||||
# Find user
|
# Find user
|
||||||
@ -220,8 +220,7 @@ class ClientUpdate(Timer):
|
|||||||
self.handle_quit = False
|
self.handle_quit = False
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
settings = bpy.context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
session_info = bpy.context.window_manager.session
|
|
||||||
session = getattr(operators, 'client', None)
|
session = getattr(operators, 'client', None)
|
||||||
renderer = getattr(presence, 'renderer', None)
|
renderer = getattr(presence, 'renderer', None)
|
||||||
|
|
||||||
@ -231,7 +230,7 @@ class ClientUpdate(Timer):
|
|||||||
bpy.ops.session.stop()
|
bpy.ops.session.stop()
|
||||||
|
|
||||||
local_user = operators.client.online_users.get(
|
local_user = operators.client.online_users.get(
|
||||||
session_info.username)
|
settings.username)
|
||||||
if not local_user:
|
if not local_user:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -8,9 +8,6 @@ from pathlib import Path
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.WARNING)
|
logger.setLevel(logging.WARNING)
|
||||||
|
|
||||||
CONFIG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config")
|
|
||||||
CONFIG = os.path.join(CONFIG_DIR, "app.yaml")
|
|
||||||
|
|
||||||
THIRD_PARTY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "libs")
|
THIRD_PARTY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "libs")
|
||||||
CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
|
CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
|
||||||
PYTHON_PATH = None
|
PYTHON_PATH = None
|
||||||
@ -19,27 +16,6 @@ SUBPROCESS_DIR = None
|
|||||||
|
|
||||||
rtypes = []
|
rtypes = []
|
||||||
|
|
||||||
|
|
||||||
def load_config():
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(CONFIG, 'r') as config_file:
|
|
||||||
return yaml.safe_load(config_file)
|
|
||||||
except FileNotFoundError:
|
|
||||||
logger.info("no config")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def save_config(config):
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
logger.info("saving config")
|
|
||||||
|
|
||||||
with open(CONFIG, 'w') as outfile:
|
|
||||||
yaml.dump(config, outfile, default_flow_style=False)
|
|
||||||
|
|
||||||
|
|
||||||
def module_can_be_imported(name):
|
def module_can_be_imported(name):
|
||||||
try:
|
try:
|
||||||
__import__(name)
|
__import__(name)
|
||||||
@ -68,9 +44,6 @@ def setup(dependencies, python_path):
|
|||||||
PYTHON_PATH = Path(python_path)
|
PYTHON_PATH = Path(python_path)
|
||||||
SUBPROCESS_DIR = PYTHON_PATH.parent
|
SUBPROCESS_DIR = PYTHON_PATH.parent
|
||||||
|
|
||||||
check_dir(CACHE_DIR)
|
|
||||||
check_dir(CONFIG_DIR)
|
|
||||||
|
|
||||||
if not module_can_be_imported("pip"):
|
if not module_can_be_imported("pip"):
|
||||||
install_pip()
|
install_pip()
|
||||||
|
|
||||||
|
@ -58,14 +58,13 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
global client, delayables, ui_context, server_process
|
global client, delayables, ui_context, server_process
|
||||||
settings = context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
runtime_settings = context.window_manager.session
|
||||||
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()
|
||||||
delayables.clear()
|
delayables.clear()
|
||||||
# save config
|
|
||||||
settings.save(context)
|
|
||||||
|
|
||||||
bpy_factory = ReplicatedDataFactory()
|
bpy_factory = ReplicatedDataFactory()
|
||||||
supported_bl_types = []
|
supported_bl_types = []
|
||||||
@ -80,7 +79,7 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
supported_bl_types.append(type_module_class.bl_id)
|
supported_bl_types.append(type_module_class.bl_id)
|
||||||
|
|
||||||
# Retreive local replicated types settings
|
# Retreive local replicated types settings
|
||||||
type_local_config = settings.supported_datablock[type_impl_name]
|
type_local_config = settings.supported_datablocks[type_impl_name]
|
||||||
|
|
||||||
bpy_factory.register_type(
|
bpy_factory.register_type(
|
||||||
type_module_class.bl_class,
|
type_module_class.bl_class,
|
||||||
@ -118,7 +117,7 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
self.report({'ERROR'}, repr(e))
|
self.report({'ERROR'}, repr(e))
|
||||||
logger.error(f"Error: {e}")
|
logger.error(f"Error: {e}")
|
||||||
finally:
|
finally:
|
||||||
settings.is_admin = True
|
runtime_settings.is_admin = True
|
||||||
|
|
||||||
# Join a session
|
# Join a session
|
||||||
else:
|
else:
|
||||||
@ -135,7 +134,7 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
self.report({'ERROR'}, repr(e))
|
self.report({'ERROR'}, repr(e))
|
||||||
logger.error(f"Error: {e}")
|
logger.error(f"Error: {e}")
|
||||||
finally:
|
finally:
|
||||||
settings.is_admin = False
|
runtime_settings.is_admin = False
|
||||||
|
|
||||||
# Background client updates service
|
# Background client updates service
|
||||||
#TODO: Refactoring
|
#TODO: Refactoring
|
||||||
@ -144,7 +143,7 @@ class SessionStartOperator(bpy.types.Operator):
|
|||||||
delayables.append(delayable.DynamicRightSelectTimer())
|
delayables.append(delayable.DynamicRightSelectTimer())
|
||||||
|
|
||||||
# Launch drawing module
|
# Launch drawing module
|
||||||
if settings.enable_presence:
|
if runtime_settings.enable_presence:
|
||||||
presence.renderer.run()
|
presence.renderer.run()
|
||||||
|
|
||||||
# Register blender main thread tools
|
# Register blender main thread tools
|
||||||
@ -226,17 +225,17 @@ class SessionPropertyRightOperator(bpy.types.Operator):
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
|
||||||
col = layout.column()
|
col = layout.column()
|
||||||
col.prop(settings, "clients")
|
col.prop(runtime_settings, "clients")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
global client
|
global client
|
||||||
|
|
||||||
if client:
|
if client:
|
||||||
client.change_owner(self.key, settings.clients)
|
client.change_owner(self.key, runtime_settings.clients)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
@ -257,13 +256,13 @@ class SessionSnapUserOperator(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
|
||||||
if settings.time_snap_running:
|
if runtime_settings.time_snap_running:
|
||||||
settings.time_snap_running = False
|
runtime_settings.time_snap_running = False
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
else:
|
else:
|
||||||
settings.time_snap_running = True
|
runtime_settings.time_snap_running = True
|
||||||
|
|
||||||
self._timer = wm.event_timer_add(0.1, window=context.window)
|
self._timer = wm.event_timer_add(0.1, window=context.window)
|
||||||
wm.modal_handler_add(self)
|
wm.modal_handler_add(self)
|
||||||
@ -311,13 +310,13 @@ class SessionSnapTimeOperator(bpy.types.Operator):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
|
||||||
if settings.user_snap_running:
|
if runtime_settings.user_snap_running:
|
||||||
settings.user_snap_running = False
|
runtime_settings.user_snap_running = False
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
else:
|
else:
|
||||||
settings.user_snap_running = True
|
runtime_settings.user_snap_running = True
|
||||||
|
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
self._timer = wm.event_timer_add(0.05, window=context.window)
|
self._timer = wm.event_timer_add(0.05, window=context.window)
|
||||||
@ -483,7 +482,7 @@ def depsgraph_evaluation(scene):
|
|||||||
context = bpy.context
|
context = bpy.context
|
||||||
blender_depsgraph = bpy.context.view_layer.depsgraph
|
blender_depsgraph = bpy.context.view_layer.depsgraph
|
||||||
dependency_updates = [u for u in blender_depsgraph.updates]
|
dependency_updates = [u for u in blender_depsgraph.updates]
|
||||||
session_infos = bpy.context.window_manager.session
|
session_infos = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
# NOTE: maybe we don't need to check each update but only the first
|
# NOTE: maybe we don't need to check each update but only the first
|
||||||
|
|
||||||
|
181
multi_user/preferences.py
Normal file
181
multi_user/preferences.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import logging
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from . import utils, bl_types
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class ReplicatedDatablock(bpy.types.PropertyGroup):
|
||||||
|
type_name: bpy.props.StringProperty()
|
||||||
|
bl_name: bpy.props.StringProperty()
|
||||||
|
bl_delay_refresh: bpy.props.FloatProperty()
|
||||||
|
bl_delay_apply: bpy.props.FloatProperty()
|
||||||
|
use_as_filter: bpy.props.BoolProperty(default=True)
|
||||||
|
auto_push: bpy.props.BoolProperty(default=True)
|
||||||
|
icon: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
class SessionPrefs(bpy.types.AddonPreferences):
|
||||||
|
bl_idname = __package__
|
||||||
|
|
||||||
|
ip: bpy.props.StringProperty(
|
||||||
|
name="ip",
|
||||||
|
description='Distant host ip',
|
||||||
|
default="127.0.0.1")
|
||||||
|
username: bpy.props.StringProperty(
|
||||||
|
name="Username",
|
||||||
|
default="user_{}".format(utils.random_string_digits())
|
||||||
|
)
|
||||||
|
client_color: bpy.props.FloatVectorProperty(
|
||||||
|
name="client_instance_color",
|
||||||
|
subtype='COLOR',
|
||||||
|
default=utils.randomColor())
|
||||||
|
port: bpy.props.IntProperty(
|
||||||
|
name="port",
|
||||||
|
description='Distant host port',
|
||||||
|
default=5555
|
||||||
|
)
|
||||||
|
supported_datablocks: bpy.props.CollectionProperty(
|
||||||
|
type=ReplicatedDatablock,
|
||||||
|
)
|
||||||
|
ipc_port: bpy.props.IntProperty(
|
||||||
|
name="ipc_port",
|
||||||
|
description='internal ttl port(only usefull for multiple local instances)',
|
||||||
|
default=5561
|
||||||
|
)
|
||||||
|
start_empty: bpy.props.BoolProperty(
|
||||||
|
name="start_empty",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
right_strategy: bpy.props.EnumProperty(
|
||||||
|
name='right_strategy',
|
||||||
|
description='right strategy',
|
||||||
|
items={
|
||||||
|
('STRICT', 'strict', 'strict right repartition'),
|
||||||
|
('COMMON', 'common', 'relaxed right repartition')},
|
||||||
|
default='COMMON')
|
||||||
|
# for UI
|
||||||
|
category: bpy.props.EnumProperty(
|
||||||
|
name="Category",
|
||||||
|
description="Preferences Category",
|
||||||
|
items=[
|
||||||
|
('INFO', "Information", "Information about this add-on"),
|
||||||
|
('CONFIG', "Configuration", "Configuration about this add-on"),
|
||||||
|
# ('UPDATE', "Update", "Update this add-on"),
|
||||||
|
],
|
||||||
|
default='INFO'
|
||||||
|
)
|
||||||
|
conf_session_identity_expanded: bpy.props.BoolProperty(
|
||||||
|
name="Identity",
|
||||||
|
description="Identity",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
conf_session_rights_expanded: bpy.props.BoolProperty(
|
||||||
|
name="Rights",
|
||||||
|
description="Rights",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
conf_session_net_expanded: bpy.props.BoolProperty(
|
||||||
|
name="Net",
|
||||||
|
description="net",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
layout.row().prop(self, "category", expand=True)
|
||||||
|
|
||||||
|
if self.category == 'INFO':
|
||||||
|
layout.separator()
|
||||||
|
layout.label(text="WIP")
|
||||||
|
if self.category == 'CONFIG':
|
||||||
|
grid = layout.column()
|
||||||
|
|
||||||
|
# USER INFORMATIONS
|
||||||
|
box = grid.box()
|
||||||
|
box.prop(
|
||||||
|
self, "conf_session_identity_expanded", text="User informations",
|
||||||
|
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_identity_expanded
|
||||||
|
else 'DISCLOSURE_TRI_RIGHT')
|
||||||
|
if self.conf_session_identity_expanded:
|
||||||
|
box.row().prop(self, "username", text="name")
|
||||||
|
box.row().prop(self, "client_color", text="color")
|
||||||
|
|
||||||
|
# NETWORK SETTINGS
|
||||||
|
box = grid.box()
|
||||||
|
box.prop(
|
||||||
|
self, "conf_session_net_expanded", text="Netorking",
|
||||||
|
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_net_expanded
|
||||||
|
else 'DISCLOSURE_TRI_RIGHT')
|
||||||
|
if self.conf_session_net_expanded:
|
||||||
|
box.row().prop(self, "ip", text="Address")
|
||||||
|
row = box.row()
|
||||||
|
row.label(text="Port:")
|
||||||
|
row.prop(self, "port", text="Address")
|
||||||
|
row = box.row()
|
||||||
|
row.label(text="Start with an empty scene:")
|
||||||
|
row.prop(self, "start_empty", text="")
|
||||||
|
|
||||||
|
line = box.row(align=True)
|
||||||
|
line.label(text=" ")
|
||||||
|
line.separator()
|
||||||
|
line.label(text="refresh (sec)")
|
||||||
|
line.label(text="apply (sec)")
|
||||||
|
|
||||||
|
for item in self.supported_datablocks:
|
||||||
|
line = box.row(align=True)
|
||||||
|
line.label(text="", icon=item.icon)
|
||||||
|
line.prop(item, "bl_delay_refresh", text="")
|
||||||
|
line.prop(item, "bl_delay_apply", text="")
|
||||||
|
# HOST SETTINGS
|
||||||
|
box = grid.box()
|
||||||
|
box.prop(
|
||||||
|
self, "conf_session_rights_expanded", text="Hosting",
|
||||||
|
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_rights_expanded
|
||||||
|
else 'DISCLOSURE_TRI_RIGHT')
|
||||||
|
if self.conf_session_rights_expanded:
|
||||||
|
box.row().prop(self, "right_strategy", text="Right model")
|
||||||
|
row = box.row()
|
||||||
|
row.label(text="Start with an empty scene:")
|
||||||
|
row.prop(self, "start_empty", text="")
|
||||||
|
|
||||||
|
def generate_supported_types(self):
|
||||||
|
self.supported_datablocks.clear()
|
||||||
|
|
||||||
|
for type in bl_types.types_to_register():
|
||||||
|
new_db = self.supported_datablocks.add()
|
||||||
|
|
||||||
|
type_module = getattr(bl_types, type)
|
||||||
|
type_impl_name = "Bl{}".format(type.split('_')[1].capitalize())
|
||||||
|
type_module_class = getattr(type_module, type_impl_name)
|
||||||
|
|
||||||
|
new_db.name = type_impl_name
|
||||||
|
new_db.type_name = type_impl_name
|
||||||
|
new_db.bl_delay_refresh = type_module_class.bl_delay_refresh
|
||||||
|
new_db.bl_delay_apply =type_module_class.bl_delay_apply
|
||||||
|
new_db.use_as_filter = True
|
||||||
|
new_db.icon = type_module_class.bl_icon
|
||||||
|
new_db.auto_push =type_module_class.bl_automatic_push
|
||||||
|
new_db.bl_name=type_module_class.bl_id
|
||||||
|
|
||||||
|
classes = (
|
||||||
|
ReplicatedDatablock,
|
||||||
|
SessionPrefs,
|
||||||
|
)
|
||||||
|
def register():
|
||||||
|
from bpy.utils import register_class
|
||||||
|
|
||||||
|
for cls in classes:
|
||||||
|
register_class(cls)
|
||||||
|
|
||||||
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
if len(prefs.supported_datablocks) == 0:
|
||||||
|
logger.info('Generating bl_types preferences')
|
||||||
|
prefs.generate_supported_types()
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
from bpy.utils import unregister_class
|
||||||
|
|
||||||
|
for cls in reversed(classes):
|
||||||
|
unregister_class(cls)
|
@ -204,7 +204,7 @@ class DrawFactory(object):
|
|||||||
self.d2d_items.clear()
|
self.d2d_items.clear()
|
||||||
|
|
||||||
def draw_client_selection(self, client_id, client_color, client_selection):
|
def draw_client_selection(self, client_id, client_color, client_selection):
|
||||||
local_user = bpy.context.window_manager.session.username
|
local_user = bpy.context.preferences.addons[__package__].preferences.username
|
||||||
|
|
||||||
if local_user != client_id:
|
if local_user != client_id:
|
||||||
self.flush_selection(client_id)
|
self.flush_selection(client_id)
|
||||||
@ -261,7 +261,7 @@ class DrawFactory(object):
|
|||||||
|
|
||||||
def draw_client_camera(self, client_id, 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.username
|
local_user = bpy.context.preferences.addons[__package__].preferences.username
|
||||||
|
|
||||||
if local_user != client_id:
|
if local_user != client_id:
|
||||||
try:
|
try:
|
||||||
|
@ -139,11 +139,12 @@ class SESSION_PT_settings_network(bpy.types.Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
# USER SETTINGS
|
# USER SETTINGS
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(settings, "session_mode", expand=True)
|
row.prop(runtime_settings, "session_mode", expand=True)
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
|
||||||
box = row.box()
|
box = row.box()
|
||||||
@ -157,7 +158,7 @@ class SESSION_PT_settings_network(bpy.types.Panel):
|
|||||||
row.label(text="IPC Port:")
|
row.label(text="IPC Port:")
|
||||||
row.prop(settings, "ipc_port", text="")
|
row.prop(settings, "ipc_port", text="")
|
||||||
|
|
||||||
if settings.session_mode == 'HOST':
|
if runtime_settings.session_mode == 'HOST':
|
||||||
row = box.row()
|
row = box.row()
|
||||||
row.label(text="Start empty:")
|
row.label(text="Start empty:")
|
||||||
row.prop(settings, "start_empty", text="")
|
row.prop(settings, "start_empty", text="")
|
||||||
@ -184,7 +185,8 @@ class SESSION_PT_settings_user(bpy.types.Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
# USER SETTINGS
|
# USER SETTINGS
|
||||||
@ -212,9 +214,11 @@ class SESSION_PT_settings_replication(bpy.types.Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
settings = context.window_manager.session
|
runtime_settings = context.window_manager.session
|
||||||
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
# Right managment
|
# Right managment
|
||||||
if settings.session_mode == 'HOST':
|
if runtime_settings.session_mode == 'HOST':
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="Right strategy:")
|
row.label(text="Right strategy:")
|
||||||
row.prop(settings,"right_strategy",text="")
|
row.prop(settings,"right_strategy",text="")
|
||||||
@ -231,7 +235,7 @@ class SESSION_PT_settings_replication(bpy.types.Panel):
|
|||||||
line.label(text="refresh (sec)")
|
line.label(text="refresh (sec)")
|
||||||
line.label(text="apply (sec)")
|
line.label(text="apply (sec)")
|
||||||
|
|
||||||
for item in settings.supported_datablock:
|
for item in settings.supported_datablocks:
|
||||||
line = flow.row(align=True)
|
line = flow.row(align=True)
|
||||||
line.prop(item, "auto_push", text="", icon=item.icon)
|
line.prop(item, "auto_push", text="", icon=item.icon)
|
||||||
line.separator()
|
line.separator()
|
||||||
@ -255,7 +259,7 @@ class SESSION_PT_user(bpy.types.Panel):
|
|||||||
layout = self.layout
|
layout = self.layout
|
||||||
online_users = context.window_manager.online_users
|
online_users = context.window_manager.online_users
|
||||||
selected_user = context.window_manager.user_index
|
selected_user = context.window_manager.user_index
|
||||||
settings = context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
active_user = online_users[selected_user] if len(online_users)-1>=selected_user else 0
|
active_user = online_users[selected_user] if len(online_users)-1>=selected_user else 0
|
||||||
|
|
||||||
|
|
||||||
@ -289,7 +293,7 @@ class SESSION_PT_user(bpy.types.Panel):
|
|||||||
class SESSION_UL_users(bpy.types.UIList):
|
class SESSION_UL_users(bpy.types.UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
|
||||||
session = operators.client
|
session = operators.client
|
||||||
settings = context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
is_local_user = item.username == settings.username
|
is_local_user = item.username == settings.username
|
||||||
ping = '-'
|
ping = '-'
|
||||||
frame_current = '-'
|
frame_current = '-'
|
||||||
@ -364,7 +368,8 @@ class SESSION_PT_services(bpy.types.Panel):
|
|||||||
|
|
||||||
|
|
||||||
def draw_property(context, parent, property_uuid, level=0):
|
def draw_property(context, parent, property_uuid, level=0):
|
||||||
settings = context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
runtime_settings = context.window_manager.session
|
||||||
item = operators.client.get(uuid=property_uuid)
|
item = operators.client.get(uuid=property_uuid)
|
||||||
|
|
||||||
if item.state == ERROR:
|
if item.state == ERROR:
|
||||||
@ -381,12 +386,12 @@ def draw_property(context, parent, property_uuid, level=0):
|
|||||||
detail_item_box = line.row(align=True)
|
detail_item_box = line.row(align=True)
|
||||||
|
|
||||||
detail_item_box.label(text="",
|
detail_item_box.label(text="",
|
||||||
icon=settings.supported_datablock[item.str_type].icon)
|
icon=settings.supported_datablocks[item.str_type].icon)
|
||||||
detail_item_box.label(text="{} ".format(name))
|
detail_item_box.label(text="{} ".format(name))
|
||||||
|
|
||||||
# Operations
|
# Operations
|
||||||
|
|
||||||
have_right_to_modify = settings.is_admin or \
|
have_right_to_modify = runtime_settings.is_admin or \
|
||||||
item.owner == settings.username or \
|
item.owner == settings.username or \
|
||||||
item.owner == RP_COMMON
|
item.owner == RP_COMMON
|
||||||
|
|
||||||
@ -444,7 +449,8 @@ class SESSION_PT_outliner(bpy.types.Panel):
|
|||||||
|
|
||||||
if hasattr(context.window_manager, 'session'):
|
if hasattr(context.window_manager, 'session'):
|
||||||
# Filters
|
# Filters
|
||||||
settings = context.window_manager.session
|
settings = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
runtime_settings = context.window_manager.session
|
||||||
flow = layout.grid_flow(
|
flow = layout.grid_flow(
|
||||||
row_major=True,
|
row_major=True,
|
||||||
columns=0,
|
columns=0,
|
||||||
@ -452,21 +458,21 @@ class SESSION_PT_outliner(bpy.types.Panel):
|
|||||||
even_rows=False,
|
even_rows=False,
|
||||||
align=True)
|
align=True)
|
||||||
|
|
||||||
for item in settings.supported_datablock:
|
for item in settings.supported_datablocks:
|
||||||
col = flow.column(align=True)
|
col = flow.column(align=True)
|
||||||
col.prop(item, "use_as_filter", text="", icon=item.icon)
|
col.prop(item, "use_as_filter", text="", icon=item.icon)
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.prop(settings, "filter_owned", text="Show only owned")
|
row.prop(runtime_settings, "filter_owned", text="Show only owned")
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
types_filter = [t.type_name for t in settings.supported_datablock
|
types_filter = [t.type_name for t in settings.supported_datablocks
|
||||||
if t.use_as_filter]
|
if t.use_as_filter]
|
||||||
|
|
||||||
key_to_filter = operators.client.list(
|
key_to_filter = operators.client.list(
|
||||||
filter_owner=settings.username) if settings.filter_owned else operators.client.list()
|
filter_owner=settings.username) if runtime_settings.filter_owned else operators.client.list()
|
||||||
|
|
||||||
client_keys = [key for key in key_to_filter
|
client_keys = [key for key in key_to_filter
|
||||||
if operators.client.get(uuid=key).str_type
|
if operators.client.get(uuid=key).str_type
|
||||||
|
@ -37,7 +37,7 @@ def find_from_attr(attr_name, attr_value, list):
|
|||||||
|
|
||||||
def get_datablock_users(datablock):
|
def get_datablock_users(datablock):
|
||||||
users = []
|
users = []
|
||||||
supported_types = bpy.context.window_manager.session.supported_datablock
|
supported_types = bpy.context.preferences.addons[__package__].preferences.supported_datablocks
|
||||||
if hasattr(datablock, 'users_collection') and datablock.users_collection:
|
if hasattr(datablock, 'users_collection') and datablock.users_collection:
|
||||||
users.extend(list(datablock.users_collection))
|
users.extend(list(datablock.users_collection))
|
||||||
if hasattr(datablock, 'users_scene') and datablock.users_scene:
|
if hasattr(datablock, 'users_scene') and datablock.users_scene:
|
||||||
@ -59,6 +59,11 @@ def random_string_digits(stringLength=6):
|
|||||||
lettersAndDigits = string.ascii_letters + string.digits
|
lettersAndDigits = string.ascii_letters + string.digits
|
||||||
return ''.join(random.choices(lettersAndDigits, k=stringLength))
|
return ''.join(random.choices(lettersAndDigits, k=stringLength))
|
||||||
|
|
||||||
|
def randomColor():
|
||||||
|
r = random.random()
|
||||||
|
v = random.random()
|
||||||
|
b = random.random()
|
||||||
|
return [r, v, b]
|
||||||
|
|
||||||
def clean_scene():
|
def clean_scene():
|
||||||
for type_name in dir(bpy.data):
|
for type_name in dir(bpy.data):
|
||||||
|
Reference in New Issue
Block a user