Compare commits

...

49 Commits

Author SHA1 Message Date
Swann 09ee1cf826 fix: auto updater download 2020-07-28 17:17:39 +02:00
Swann Martinez 61bcec98c3 fix: wrong debian version 2020-07-28 13:37:06 +00:00
Swann Martinez 1c85d436fd feat: missing update 2020-07-28 13:32:33 +00:00
Swann Martinez 03318026d4 feat: missing zip program 2020-07-28 13:26:54 +00:00
Swann Martinez 7a0b142d69 feat: zip build artifacts 2020-07-28 13:20:35 +00:00
Swann eb874110f8 Merge branch 'develop' 2020-07-28 14:25:42 +02:00
Swann 6e0c7bc332 clean disable armature missing roll 2020-07-28 12:06:58 +02:00
Swann ee83e61b09 fix: None image 2020-07-28 12:05:26 +02:00
Swann 99b2dc0539 refactor: increase use line width 2020-07-28 12:05:04 +02:00
Swann 53f1118181 refactor: update download links 2020-07-27 17:44:27 +02:00
Swann 2791264a92 feat: empty image support 2020-07-24 21:38:00 +02:00
Swann 6c2ee0cad3 refactor: lobby ui 2020-07-24 16:02:19 +02:00
Swann 20f8c25f55 refactor: timeout update 2020-07-24 14:58:07 +02:00
Swann 0224f55104 refactor: change the timeout 2020-07-24 14:57:39 +02:00
Swann 644702ebdf feat: client state update as soon a client are in the lobby 2020-07-24 14:56:20 +02:00
Swann 9377b2be9b fix: session pannel title 2020-07-24 14:55:14 +02:00
Swann 29cbf23142 doc: update hosting guide 2020-07-24 14:53:44 +02:00
Swann a645f71d19 fix: material socket index
Related to #101
2020-07-22 16:41:01 +02:00
Swann 909d92a7a1 fix: broken materials links
Related to #102
2020-07-21 16:46:16 +02:00
Swann 7ee9089087 feat: use callbacks instead of timers to cleanup session states
refactor: move graph initialization to operators,py
2020-07-17 16:33:39 +02:00
Swann 6201c82392 fix: Loading the false scene by default
`get` was giving wrong result inthe  scene initialization routing during the  resolve process

Related to #100
2020-07-17 14:47:52 +02:00
Swann 0faf7d9436 fix: initial test to handle #99 2020-07-15 19:08:53 +02:00
Swann e69e61117a fix: Process "Quitting session" does not finish and gets stuck
Related to #101
2020-07-15 14:46:48 +02:00
Swann 25e988d423 fix: Unregistration of users
Related to #97
2020-07-15 13:50:46 +02:00
Swann Martinez 8a3ab895e0 fix: ci blender install 2020-07-14 12:56:34 +00:00
Swann 06a8e3c0ab feat: replication update 2020-07-14 14:54:22 +02:00
Swann Martinez c1c1628a38 Update .gitlab/ci/test.gitlab-ci.yml 2020-07-14 10:07:30 +00:00
Swann 022e3354d9 feat: psutils test 2020-07-14 11:59:45 +02:00
Swann 211cb848b9 feat: update replication version 2020-07-14 11:29:30 +02:00
Swann 25e233f328 fix: temporary disabled spline IK test until the python api is fixed 2020-07-13 15:57:19 +02:00
Swann 9bc3d9b29d feat: dependencies version check 2020-07-13 15:12:15 +02:00
Swann 15debf339d feat: auto-update dependencies 2020-07-10 18:00:44 +02:00
Swann 56df7d182d clean: remove libs 2020-07-10 17:05:42 +02:00
Swann 26e1579e35 feat: update ci 2020-07-10 16:59:47 +02:00
Swann a0e290ad6d feat: remove submodule 2020-07-10 16:59:32 +02:00
Swann 092384b2e4 feat: use replication from pip 2020-07-10 16:50:09 +02:00
Swann 2dc3654e6c feat: tests
feat: services heartbeats
clean: remove psutil dependency
2020-07-09 22:10:26 +02:00
Swann f37a9efc60 feat: orthographic correction 2020-07-09 15:52:42 +02:00
Swann 0c5d323063 clean: remove old modal operator queue 2020-07-09 15:17:45 +02:00
Swann b9f1b8a871 fix: armature operator is not running 2020-07-08 18:09:00 +02:00
Swann 2f6d8e1701 feat: initial camera background image support 2020-07-07 17:09:37 +02:00
Swann 9e64584f2d fix: ZeroDivisionError: integer division or modulo by zero 2020-07-07 15:50:05 +02:00
Swann Martinez 154aaf71c8 fix: disable test 2020-07-07 13:32:30 +00:00
Swann Martinez ac24ab69ff fix: revert and disable testing until a definitive fix 2020-07-07 13:29:08 +00:00
Swann Martinez ad431378f8 fix: test with a debian based image 2020-07-07 13:18:34 +00:00
Swann Martinez 784506cd95 fix: update build file 2020-07-07 13:07:55 +00:00
Swann Martinez eb7542b1dd fix: update test.gitlab-ic.yml 2020-07-07 12:44:58 +00:00
Swann Martinez a0676f4e37 hotfix: wrong download link 2020-03-14 20:30:18 +00:00
Swann 61a05dc347 fix: curve commit error
Releated to #72
2020-03-10 18:04:06 +01:00
25 changed files with 242 additions and 155 deletions
+1 -2
View File
@@ -4,5 +4,4 @@ stages:
include:
- local: .gitlab/ci/test.gitlab-ci.yml
- local: .gitlab/ci/build.gitlab-ci.yml
- local: .gitlab/ci/build.gitlab-ci.yml
+2 -4
View File
@@ -1,10 +1,7 @@
build:
stage: build
image: python:latest
image: debian:stable-slim
script:
- git submodule init
- git submodule update
- cd multi_user/libs/replication
- rm -rf tests .git .gitignore script
artifacts:
@@ -12,3 +9,4 @@ build:
paths:
- multi_user
+5 -5
View File
@@ -1,14 +1,14 @@
test:
stage: test
image: python:latest
image: python:3.7
script:
- git submodule init
- git submodule update
- apt update
- apt-get update
# install blender to get all required dependencies
# TODO: indtall only dependencies
- apt install -f -y gcc python-dev python3.7-dev
- apt install -f -y blender
- python3 -m pip install blender-addon-tester
- python3 scripts/test_addon.py
- python -m pip install blender-addon-tester
- python scripts/test_addon.py
-3
View File
@@ -1,3 +0,0 @@
[submodule "multi_user/libs/replication"]
path = multi_user/libs/replication
url = https://gitlab.com/slumber/replication.git
+1 -1
View File
@@ -11,7 +11,7 @@ This tool aims to allow multiple users to work on the same scene over the networ
## Quick installation
1. Download latest release [multi_user.zip](/uploads/8aef79c7cf5b1d9606dc58307fd9ad8b/multi_user.zip).
1. Download latest release [multi_user.zip](https://gitlab.com/slumber/multi-user/-/jobs/artifacts/master/download?job=build).
2. Run blender as administrator (dependencies installation).
3. Install last_version.zip from your addon preferences.
+5 -6
View File
@@ -186,25 +186,24 @@ Using a regular command line
You can run the dedicated server on any platform by following those steps:
1. Firstly, download and intall python 3 (3.6 or above).
2. Download and extract the dedicated server from `here <https://gitlab.com/slumber/replication/-/archive/develop/replication-develop.zip>`_
3. Open a terminal in the extracted folder and install python dependencies by running:
2. Install the replication library:
.. code-block:: bash
python -m pip install -r requirements.txt
python -m pip install replication
4. Launch the server from the same terminal with:
4. Launch the server with:
.. code-block:: bash
python scripts/server.py
replication.serve
.. hint::
You can also specify a custom **port** (-p), **timeout** (-t) and **admin password** (-pwd) with the following optionnal argument
.. code-block:: bash
python scripts/server.py -p 5555 -pwd toto -t 1000
replication.serve -p 5555 -pwd toto -t 1000
As soon as the dedicated server is running, you can connect to it from blender (follow :ref:`how-to-join`).
+4 -11
View File
@@ -21,7 +21,7 @@ bl_info = {
"author": "Swann Martinez",
"version": (0, 0, 3),
"description": "Enable real-time collaborative workflow inside blender",
"blender": (2, 80, 0),
"blender": (2, 82, 0),
"location": "3D View > Sidebar > Multi-User tab",
"warning": "Unstable addon, use it at your own risks",
"category": "Collaboration",
@@ -45,22 +45,15 @@ from . import environment, utils
# TODO: remove dependency as soon as replication will be installed as a module
DEPENDENCIES = {
("zmq","zmq"),
("jsondiff","jsondiff"),
("deepdiff", "deepdiff"),
("psutil","psutil")
("replication", '0.0.20'),
("deepdiff", '5.0.1'),
}
libs = os.path.dirname(os.path.abspath(__file__))+"\\libs\\replication\\replication"
def register():
# Setup logging policy
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
if libs not in sys.path:
sys.path.append(libs)
try:
environment.setup(DEPENDENCIES, bpy.app.binary_path_python)
except ModuleNotFoundError:
+13 -12
View File
@@ -722,21 +722,22 @@ class Singleton_updater(object):
self._source_zip = os.path.join(local,"source.zip")
if self._verbose: print("Starting download update zip")
if self._verbose: print(f"Starting download update zip to {self._source_zip}")
try:
request = urllib.request.Request(url)
context = ssl._create_unverified_context()
import urllib3
http = urllib3.PoolManager()
r = http.request('GET', url, preload_content=False)
chunk_size = 1024*8
with open(self._source_zip, 'wb') as out:
while True:
data = r.read(chunk_size)
if not data:
break
out.write(data)
# setup private token if appropriate
if self._engine.token != None:
if self._engine.name == "gitlab":
request.add_header('PRIVATE-TOKEN',self._engine.token)
else:
if self._verbose: print("Tokens not setup for selected engine yet")
self.urlretrieve(urllib.request.urlopen(request,context=context), self._source_zip)
# add additional checks on file size being non-zero
r.release_conn()
if self._verbose: print("Successfully downloaded update zip")
return True
return False
except Exception as e:
self._error = "Error retrieving download, bad link?"
self._error_msg = "Error: {}".format(e)
+1 -1
View File
@@ -38,7 +38,7 @@ __all__ = [
] # Order here defines execution order
from . import *
from ..libs.replication.replication.data import ReplicatedDataFactory
from replication.data import ReplicatedDataFactory
def types_to_register():
return __all__
+3 -1
View File
@@ -92,6 +92,7 @@ class BlArmature(BlDatablock):
new_bone.head = bone_data['head_local']
new_bone.tail_radius = bone_data['tail_radius']
new_bone.head_radius = bone_data['head_radius']
# new_bone.roll = bone_data['roll']
if 'parent' in bone_data:
new_bone.parent = target.edit_bones[data['bones']
@@ -123,7 +124,8 @@ class BlArmature(BlDatablock):
'use_connect',
'parent',
'name',
'layers'
'layers',
# 'roll',
]
data = dumper.dump(instance)
+29 -3
View File
@@ -36,7 +36,7 @@ class BlCamera(BlDatablock):
def _load_implementation(self, data, target):
loader = Loader()
loader = Loader()
loader.load(target, data)
dof_settings = data.get('dof')
@@ -45,13 +45,22 @@ class BlCamera(BlDatablock):
if dof_settings:
loader.load(target.dof, dof_settings)
background_images = data.get('background_images')
if background_images:
target.background_images.clear()
for img_name, img_data in background_images.items():
target_img = target.background_images.new()
target_img.image = bpy.data.images[img_name]
loader.load(target_img, img_data)
def _dump_implementation(self, data, instance=None):
assert(instance)
# TODO: background image support
dumper = Dumper()
dumper.depth = 2
dumper.depth = 3
dumper.include_filter = [
"name",
'type',
@@ -79,7 +88,24 @@ class BlCamera(BlDatablock):
'sensor_fit',
'sensor_height',
'sensor_width',
'show_background_images',
'background_images',
'alpha',
'display_depth',
'frame_method',
'offset',
'rotation',
'scale',
'use_flip_x',
'use_flip_y',
'image'
]
return dumper.dump(instance)
def _resolve_deps_implementation(self):
deps = []
for background in self.instance.background_images:
if background.image:
deps.append(background.image)
return deps
+6 -5
View File
@@ -21,8 +21,8 @@ import mathutils
from .. import utils
from .dump_anything import Loader, Dumper
from ..libs.replication.replication.data import ReplicatedDatablock
from ..libs.replication.replication.constants import (UP, DIFF_BINARY)
from replication.data import ReplicatedDatablock
from replication.constants import (UP, DIFF_BINARY)
def has_action(target):
@@ -117,9 +117,10 @@ class BlDatablock(ReplicatedDatablock):
datablock_ref = utils.find_from_attr('uuid', self.uuid, datablock_root)
if not datablock_ref:
datablock_ref = datablock_root.get(
self.data['name'], # Resolve by name
self._construct(data=self.data)) # If it doesn't exist create it
try:
datablock_ref = datablock_root[self.data['name']]
except Exception:
datablock_ref = self._construct(data=self.data)
if datablock_ref:
setattr(datablock_ref, 'uuid', self.uuid)
+1 -1
View File
@@ -21,7 +21,7 @@ import mathutils
from .dump_anything import Dumper, Loader, np_dump_collection, np_load_collection
from .bl_datablock import BlDatablock
from ..libs.replication.replication.exception import ContextError
from replication.exception import ContextError
POINT = ['co', 'weight_softbody', 'co_deform']
+19 -19
View File
@@ -19,11 +19,13 @@
import bpy
import mathutils
import logging
import re
from .. import utils
from .dump_anything import Loader, Dumper
from .bl_datablock import BlDatablock
NODE_SOCKET_INDEX = re.compile('\[(\d*)\]')
def load_node(node_data, node_tree):
""" Load a node into a node_tree from a dict
@@ -36,21 +38,20 @@ def load_node(node_data, node_tree):
loader = Loader()
target_node = node_tree.nodes.new(type=node_data["bl_idname"])
loader.load(target_node, node_data)
loader.load(target_node, node_data)
for input in node_data["inputs"]:
if hasattr(target_node.inputs[input], "default_value"):
try:
target_node.inputs[input].default_value = node_data["inputs"][input]["default_value"]
except:
logging.error(f"Material {input} parameter not supported, skipping")
logging.error(
f"Material {input} parameter not supported, skipping")
def load_links(links_data, node_tree):
""" Load node_tree links from a list
:arg links_data: dumped node links
:type links_data: list
:arg node_tree: node links collection
@@ -60,7 +61,6 @@ def load_links(links_data, node_tree):
for link in links_data:
input_socket = node_tree.nodes[link['to_node']].inputs[int(link['to_socket'])]
output_socket = node_tree.nodes[link['from_node']].outputs[int(link['from_socket'])]
node_tree.links.new(input_socket, output_socket)
@@ -75,11 +75,13 @@ def dump_links(links):
links_data = []
for link in links:
to_socket = NODE_SOCKET_INDEX.search(link.to_socket.path_from_id()).group(1)
from_socket = NODE_SOCKET_INDEX.search(link.from_socket.path_from_id()).group(1)
links_data.append({
'to_node':link.to_node.name,
'to_socket':link.to_socket.path_from_id()[-2:-1],
'from_node':link.from_node.name,
'from_socket':link.from_socket.path_from_id()[-2:-1],
'to_node': link.to_node.name,
'to_socket': to_socket,
'from_node': link.from_node.name,
'from_socket': from_socket,
})
return links_data
@@ -118,7 +120,7 @@ def dump_node(node):
"outputs",
"width_hidden"
]
dumped_node = node_dumper.dump(node)
if hasattr(node, 'inputs'):
@@ -151,7 +153,7 @@ def dump_node(node):
'location'
]
dumped_node['mapping'] = curve_dumper.dump(node.mapping)
return dumped_node
@@ -176,15 +178,14 @@ class BlMaterial(BlDatablock):
loader.load(
target.grease_pencil, data['grease_pencil'])
if data["use_nodes"]:
if target.node_tree is None:
target.use_nodes = True
target.node_tree.nodes.clear()
loader.load(target,data)
loader.load(target, data)
# Load nodes
for node in data["node_tree"]["nodes"]:
load_node(data["node_tree"]["nodes"][node], target.node_tree)
@@ -221,9 +222,9 @@ class BlMaterial(BlDatablock):
for node in instance.node_tree.nodes:
nodes[node.name] = dump_node(node)
data["node_tree"]['nodes'] = nodes
data["node_tree"]["links"] = dump_links(instance.node_tree.links)
if instance.is_grease_pencil:
gp_mat_dumper = Dumper()
gp_mat_dumper.depth = 3
@@ -248,7 +249,7 @@ class BlMaterial(BlDatablock):
'texture_clamp',
'gradient_type',
'mix_color',
'flip'
'flip'
]
data['grease_pencil'] = gp_mat_dumper.dump(instance.grease_pencil)
return data
@@ -265,4 +266,3 @@ class BlMaterial(BlDatablock):
deps.append(self.instance.library)
return deps
+2 -2
View File
@@ -23,8 +23,8 @@ import logging
import numpy as np
from .dump_anything import Dumper, Loader, np_load_collection_primitives, np_dump_collection_primitive, np_load_collection, np_dump_collection
from ..libs.replication.replication.constants import DIFF_BINARY
from ..libs.replication.replication.exception import ContextError
from replication.constants import DIFF_BINARY
from replication.exception import ContextError
from .bl_datablock import BlDatablock
+16 -1
View File
@@ -22,7 +22,7 @@ import logging
from .dump_anything import Loader, Dumper
from .bl_datablock import BlDatablock
from ..libs.replication.replication.exception import ContextError
from replication.exception import ContextError
def load_pose(target_bone, data):
@@ -152,6 +152,13 @@ class BlObject(BlDatablock):
target.data.shape_keys.key_blocks[key_block].relative_key = target.data.shape_keys.key_blocks[reference]
# TODO: find another way...
if target.type == 'EMPTY':
img_key = data.get('data')
if target.data is None and img_key:
target.data = bpy.data.images.get(img_key, None)
def _dump_implementation(self, data, instance=None):
assert(instance)
@@ -171,6 +178,14 @@ class BlObject(BlDatablock):
"library",
"empty_display_type",
"empty_display_size",
"empty_image_offset",
"empty_image_depth",
"empty_image_side",
"show_empty_image_orthographic",
"show_empty_image_perspective",
"show_empty_image_only_axis_aligned",
"use_empty_image_alpha",
"color"
"instance_collection",
"instance_type",
"location",
+30 -25
View File
@@ -20,7 +20,7 @@ import logging
import bpy
from . import operators, presence, utils
from .libs.replication.replication.constants import (FETCHED,
from replication.constants import (FETCHED,
RP_COMMON,
STATE_INITIAL,
STATE_QUITTING,
@@ -239,7 +239,7 @@ class DrawClient(Draw):
class ClientUpdate(Timer):
def __init__(self, timout=.016):
def __init__(self, timout=.032):
super().__init__(timout)
self.handle_quit = False
self.users_metadata = {}
@@ -298,31 +298,36 @@ class ClientUpdate(Timer):
local_user_metadata['view_corners'] = current_view_corners
local_user_metadata['view_matrix'] = presence.get_view_matrix()
session.update_user_metadata(local_user_metadata)
# 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)
renderer.flush_selection()
renderer.flush_users()
break
class SessionStatusUpdate(Timer):
def __init__(self, timout=1):
super().__init__(timout)
for user in session_users:
if user not in ui_users:
new_key = ui_users.add()
new_key.name = user
new_key.username = user
elif session.state['STATE'] == STATE_QUITTING:
presence.refresh_sidebar_view()
self.handle_quit = True
elif session.state['STATE'] == STATE_INITIAL and self.handle_quit:
self.handle_quit = False
presence.refresh_sidebar_view()
def execute(self):
presence.refresh_sidebar_view()
operators.unregister_delayables()
class SessionUserSync(Timer):
def __init__(self, timout=1):
super().__init__(timout)
presence.renderer.stop()
def execute(self):
session = getattr(operators, 'client', None)
renderer = getattr(presence, 'renderer', None)
presence.refresh_sidebar_view()
if session and renderer:
# 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)
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
new_key.username = user
+23 -6
View File
@@ -23,6 +23,9 @@ import subprocess
import sys
from pathlib import Path
import socket
import re
VERSION_EXPR = re.compile('\d+\.\d+\.\d+')
THIRD_PARTY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "libs")
DEFAULT_CACHE_DIR = os.path.join(
@@ -47,10 +50,22 @@ def install_pip():
subprocess.run([str(PYTHON_PATH), "-m", "ensurepip"])
def install_package(name):
logging.debug(f"Using {PYTHON_PATH} for installation")
subprocess.run([str(PYTHON_PATH), "-m", "pip", "install", name])
def install_package(name, version):
logging.info(f"installing {name} version...")
subprocess.run([str(PYTHON_PATH), "-m", "pip", "install", f"{name}=={version}"])
def check_package_version(name, required_version):
logging.info(f"Checking {name} version...")
out = subprocess.run(f"{str(PYTHON_PATH)} -m pip show {name}", capture_output=True)
version = VERSION_EXPR.search(out.stdout.decode())
if version and version.group() == required_version:
logging.info(f"{name} is up to date")
return True
else:
logging.info(f"{name} need an update")
return False
def get_ip():
"""
@@ -78,7 +93,9 @@ def setup(dependencies, python_path):
if not module_can_be_imported("pip"):
install_pip()
for module_name, package_name in dependencies:
if not module_can_be_imported(module_name):
install_package(package_name)
for package_name, package_version in dependencies:
if not module_can_be_imported(package_name):
install_package(package_name, package_version)
module_can_be_imported(package_name)
elif not check_package_version(package_name, package_version):
install_package(package_name, package_version)
View File
+41 -26
View File
@@ -33,31 +33,19 @@ import mathutils
from bpy.app.handlers import persistent
from . import bl_types, delayable, environment, presence, ui, utils
from .libs.replication.replication.constants import (FETCHED, STATE_ACTIVE,
from replication.constants import (FETCHED, STATE_ACTIVE,
STATE_INITIAL,
STATE_SYNCING)
from .libs.replication.replication.data import ReplicatedDataFactory
from .libs.replication.replication.exception import NonAuthorizedOperationError
from .libs.replication.replication.interface import Session
from replication.data import ReplicatedDataFactory
from replication.exception import NonAuthorizedOperationError
from replication.interface import Session
client = None
delayables = []
stop_modal_executor = False
modal_executor_queue = None
def unregister_delayables():
global delayables, stop_modal_executor
for d in delayables:
try:
d.unregister()
except:
continue
stop_modal_executor = True
# OPERATORS
@@ -80,7 +68,6 @@ class SessionStartOperator(bpy.types.Operator):
users = bpy.data.window_managers['WinMan'].online_users
admin_pass = runtime_settings.password
unregister_delayables()
users.clear()
delayables.clear()
@@ -163,16 +150,44 @@ class SessionStartOperator(bpy.types.Operator):
delayables.append(delayable.DrawClient())
delayables.append(delayable.DynamicRightSelectTimer())
# Launch drawing module
if runtime_settings.enable_presence:
presence.renderer.run()
session_update = delayable.SessionStatusUpdate()
session_user_sync = delayable.SessionUserSync()
session_update.register()
session_user_sync.register()
# Register blender main thread tools
for d in delayables:
d.register()
delayables.append(session_update)
delayables.append(session_user_sync)
@client.register('on_connection')
def initialize_session():
for node in client._graph.list_ordered():
node_ref = client.get(node)
if node_ref.state == FETCHED:
node_ref.resolve()
node_ref.apply()
# Launch drawing module
if runtime_settings.enable_presence:
presence.renderer.run()
# Register blender main thread tools
for d in delayables:
d.register()
@client.register('on_exit')
def desinitialize_session():
global delayables, stop_modal_executor
for d in delayables:
try:
d.unregister()
except:
continue
stop_modal_executor = True
presence.renderer.stop()
global modal_executor_queue
modal_executor_queue = queue.Queue()
bpy.ops.session.apply_armature_operator()
self.report(
@@ -527,7 +542,7 @@ class ApplyArmatureOperator(bpy.types.Operator):
try:
client.apply(node)
except Exception as e:
logging.error("Dail to apply armature: {e}")
logging.error("Fail to apply armature: {e}")
return {'PASS_THROUGH'}
+1 -1
View File
@@ -22,7 +22,7 @@ import string
import re
from . import utils, bl_types, environment, addon_updater_ops, presence, ui
from .libs.replication.replication.constants import RP_COMMON
from replication.constants import RP_COMMON
IP_EXPR = re.compile('\d+\.\d+\.\d+\.\d+')
+3 -2
View File
@@ -19,6 +19,7 @@
import copy
import logging
import math
import traceback
import bgl
import blf
@@ -311,10 +312,10 @@ class DrawFactory(object):
self.d2d_items[client_id] = (position[1], client_id, color)
except Exception as e:
logging.error(f"Draw client exception: {e}")
logging.debug(f"Draw client exception: {e} \n {traceback.format_exc()}\n pos:{position},ind:{indices}")
def draw3d_callback(self):
bgl.glLineWidth(1.5)
bgl.glLineWidth(2.)
bgl.glEnable(bgl.GL_DEPTH_TEST)
bgl.glEnable(bgl.GL_BLEND)
bgl.glEnable(bgl.GL_LINE_SMOOTH)
+33 -16
View File
@@ -19,7 +19,7 @@
import bpy
from . import operators, utils
from .libs.replication.replication.constants import (ADDED, ERROR, FETCHED,
from replication.constants import (ADDED, ERROR, FETCHED,
MODIFIED, RP_COMMON, UP,
STATE_ACTIVE, STATE_AUTH,
STATE_CONFIG, STATE_SYNCING,
@@ -50,6 +50,8 @@ def printProgressBar(iteration, total, prefix='', suffix='', decimals=1, length=
From here:
https://gist.github.com/greenstick/b23e475d2bfdc3a82e34eaa1f6781ee4
"""
if total == 0:
return ""
filledLength = int(length * iteration // total)
bar = fill * filledLength + fill_empty * (length - filledLength)
return f"{prefix} |{bar}| {iteration}/{total}{suffix}"
@@ -84,7 +86,7 @@ def get_state_str(state):
class SESSION_PT_settings(bpy.types.Panel):
"""Settings panel"""
bl_idname = "MULTIUSER_SETTINGS_PT_panel"
bl_label = ""
bl_label = " "
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Multiuser"
@@ -126,14 +128,18 @@ class SESSION_PT_settings(bpy.types.Panel):
current_state = cli_state['STATE']
# STATE ACTIVE
if current_state in [STATE_ACTIVE, STATE_LOBBY]:
if current_state in [STATE_ACTIVE]:
row.operator("session.stop", icon='QUIT', text="Exit")
row = layout.row()
if runtime_settings.is_host:
row = row.box()
row.label(text=f"{runtime_settings.internet_ip}:{settings.port}", icon='INFO')
row.label(text=f"LAN: {runtime_settings.internet_ip}", icon='INFO')
row = layout.row()
if current_state == STATE_LOBBY:
row = row.box()
row.label(text=f"Waiting the session to start", icon='INFO')
row = layout.row()
row.operator("session.stop", icon='QUIT', text="Exit")
# CONNECTION STATE
elif current_state in [STATE_SRV_SYNC,
STATE_SYNCING,
@@ -356,17 +362,19 @@ class SESSION_PT_user(bpy.types.Panel):
if active_user != 0 and active_user.username != settings.username:
row = layout.row()
user_operations = row.split()
user_operations.alert = context.window_manager.session.time_snap_running
user_operations.operator(
"session.snapview",
text="",
icon='VIEW_CAMERA').target_client = active_user.username
if operators.client.state['STATE'] == STATE_ACTIVE:
user_operations.alert = context.window_manager.session.time_snap_running
user_operations.operator(
"session.snapview",
text="",
icon='VIEW_CAMERA').target_client = active_user.username
user_operations.alert = context.window_manager.session.user_snap_running
user_operations.operator(
"session.snaptime",
text="",
icon='TIME').target_client = active_user.username
user_operations.alert = context.window_manager.session.user_snap_running
user_operations.operator(
"session.snaptime",
text="",
icon='TIME').target_client = active_user.username
if operators.client.online_users[settings.username]['admin']:
user_operations.operator(
@@ -532,9 +540,18 @@ class SESSION_PT_repository(bpy.types.Panel):
@classmethod
def poll(cls, context):
session = operators.client
settings = utils.get_preferences()
admin = False
if session and hasattr(session,'online_users'):
usr = session.online_users.get(settings.username)
if usr:
admin = usr['admin']
return hasattr(context.window_manager, 'session') and \
operators.client and \
operators.client.state['STATE'] in [STATE_ACTIVE, STATE_LOBBY]
(operators.client.state['STATE'] == STATE_ACTIVE or \
operators.client.state['STATE'] == STATE_LOBBY and admin)
def draw_header(self, context):
self.layout.label(text="", icon='OUTLINER_OB_GROUP_INSTANCE')
+3 -1
View File
@@ -30,9 +30,11 @@ CONSTRAINTS_TYPES = [
'COPY_ROTATION', 'COPY_SCALE', 'COPY_TRANSFORMS', 'LIMIT_DISTANCE',
'LIMIT_LOCATION', 'LIMIT_ROTATION', 'LIMIT_SCALE', 'MAINTAIN_VOLUME',
'TRANSFORM', 'TRANSFORM_CACHE', 'CLAMP_TO', 'DAMPED_TRACK', 'IK',
'LOCKED_TRACK', 'SPLINE_IK', 'STRETCH_TO', 'TRACK_TO', 'ACTION',
'LOCKED_TRACK', 'STRETCH_TO', 'TRACK_TO', 'ACTION',
'ARMATURE', 'CHILD_OF', 'FLOOR', 'FOLLOW_PATH', 'PIVOT', 'SHRINKWRAP']
#temporary disabled 'SPLINE_IK' until its fixed
def test_object(clear_blend):
bpy.ops.mesh.primitive_cube_add(
enter_editmode=False, align='WORLD', location=(0, 0, 0))