diff --git a/multi_user/bl_types/bl_file.py b/multi_user/bl_types/bl_file.py index cc3b5e5..8562230 100644 --- a/multi_user/bl_types/bl_file.py +++ b/multi_user/bl_types/bl_file.py @@ -19,7 +19,7 @@ import logging import os import sys -from pathlib import Path +from pathlib import Path, WindowsPath, PosixPath import bpy import mathutils @@ -59,32 +59,16 @@ class BlFile(ReplicatedDatablock): bl_icon = 'FILE' bl_reload_parent = True - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.instance = kwargs.get('instance', None) - - if self.instance and not self.instance.exists(): - raise FileNotFoundError(str(self.instance)) + @staticmethod + def construct(data: dict) -> object: + return Path(get_filepath(data['name'])) + @staticmethod + def resolve(data: dict) -> object: + return Path(get_filepath(data['name'])) - def resolve(self, construct = True): - self.instance = Path(get_filepath(self.data['name'])) - - file_exists = self.instance.exists() - if not file_exists: - logging.debug("File don't exist, loading it.") - self._load(self.data, self.instance) - - return file_exists - - - def push(self, socket, identity=None, check_data=False): - super().push(socket, identity=None, check_data=False) - - if get_preferences().clear_memory_filecache: - del self.data['file'] - - def _dump(self, instance=None): + @staticmethod + def dump(datablock: object) -> dict: """ Read the file and return a dict as: { @@ -96,37 +80,37 @@ class BlFile(ReplicatedDatablock): logging.info(f"Extracting file metadata") data = { - 'name': self.instance.name, + 'name': datablock.name, } - logging.info( - f"Reading {self.instance.name} content: {self.instance.stat().st_size} bytes") + logging.info(f"Reading {datablock.name} content: {datablock.stat().st_size} bytes") try: - file = open(self.instance, "rb") + file = open(datablock, "rb") data['file'] = file.read() file.close() except IOError: - logging.warning(f"{self.instance} doesn't exist, skipping") + logging.warning(f"{datablock} doesn't exist, skipping") else: file.close() return data - def _load(self, data, target): + @staticmethod + def load(data: dict, datablock: object): """ Writing the file """ try: - file = open(target, "wb") + file = open(datablock, "wb") file.write(data['file']) if get_preferences().clear_memory_filecache: - del self.data['file'] + del data['file'] except IOError: - logging.warning(f"{target} doesn't exist, skipping") + logging.warning(f"{datablock} doesn't exist, skipping") else: file.close() @@ -134,16 +118,23 @@ class BlFile(ReplicatedDatablock): if get_preferences().clear_memory_filecache: return False else: - if not self.instance: + if not datablock: return None if not self.data: return super().diff() memory_size = sys.getsizeof(self.data['file'])-33 - disk_size = self.instance.stat().st_size + disk_size = datablock.stat().st_size if memory_size != disk_size: return super().diff() else: return None + + @staticmethod + def resolve_deps(datablock: object) -> [object]: + return [] + +_type = [WindowsPath, PosixPath] +_class = BlFile \ No newline at end of file diff --git a/multi_user/bl_types/bl_image.py b/multi_user/bl_types/bl_image.py index 7097fc0..12e24c1 100644 --- a/multi_user/bl_types/bl_image.py +++ b/multi_user/bl_types/bl_image.py @@ -27,6 +27,9 @@ from .. import utils from replication.protocol import ReplicatedDatablock from .dump_anything import Dumper, Loader from .bl_file import get_filepath, ensure_unpacked +from .bl_datablock import resolve_datablock_from_uuid +from .bl_action import dump_animation_data, load_animation_data, resolve_animation_dependencies + format_to_ext = { 'BMP': 'bmp', @@ -55,6 +58,7 @@ class BlImage(ReplicatedDatablock): bl_icon = 'IMAGE_DATA' bl_reload_parent = False + @staticmethod def construct(data: dict) -> object: return bpy.data.images.new( name=data['name'], @@ -62,21 +66,21 @@ class BlImage(ReplicatedDatablock): height=data['size'][1] ) - def _load(self, data, target): + @staticmethod + def load(data: dict, datablock: object): loader = Loader() - loader.load(data, target) + loader.load(data, datablock) - target.source = 'FILE' - target.filepath_raw = get_filepath(data['filename']) + datablock.source = 'FILE' + datablock.filepath_raw = get_filepath(data['filename']) color_space_name = data["colorspace_settings"]["name"] if color_space_name: - target.colorspace_settings.name = color_space_name + datablock.colorspace_settings.name = color_space_name - def _dump(self, instance=None): - assert(instance) - - filename = Path(instance.filepath).name + @staticmethod + def dump(datablock: object) -> dict: + filename = Path(datablock.filepath).name data = { "filename": filename @@ -93,9 +97,10 @@ class BlImage(ReplicatedDatablock): 'float_buffer', 'alpha_mode', 'colorspace_settings'] - data.update(dumper.dump(instance)) + data.update(dumper.dump(datablock)) return data + def diff(self): if self.instance.is_dirty: self.instance.save() @@ -105,23 +110,38 @@ class BlImage(ReplicatedDatablock): else: return None + @staticmethod + def resolve(data: dict) -> object: + uuid = data.get('uuid') + name = data.get('name') + datablock = resolve_datablock_from_uuid(uuid, bpy.data.images) + if datablock is None: + datablock = bpy.data.images.get(name) + + return datablock + + @staticmethod def resolve_deps(datablock: object) -> [object]: deps = [] - if self.instance.packed_file: - filename = Path(bpy.path.abspath(self.instance.filepath)).name - self.instance.filepath_raw = get_filepath(filename) - self.instance.save() + if datablock.packed_file: + filename = Path(bpy.path.abspath(datablock.filepath)).name + datablock.filepath_raw = get_filepath(filename) + datablock.save() # An image can't be unpacked to the modified path # TODO: make a bug report - self.instance.unpack(method="REMOVE") + datablock.unpack(method="REMOVE") - elif self.instance.source == "GENERATED": - filename = f"{self.instance.name}.png" - self.instance.filepath = get_filepath(filename) - self.instance.save() + elif datablock.source == "GENERATED": + filename = f"{datablock.name}.png" + datablock.filepath = get_filepath(filename) + datablock.save() - if self.instance.filepath: - deps.append(Path(bpy.path.abspath(self.instance.filepath))) + if datablock.filepath: + deps.append(Path(bpy.path.abspath(datablock.filepath))) return deps + + +_type = bpy.types.Image +_class = BlImage diff --git a/multi_user/bl_types/bl_material.py b/multi_user/bl_types/bl_material.py index b356211..556632b 100644 --- a/multi_user/bl_types/bl_material.py +++ b/multi_user/bl_types/bl_material.py @@ -48,7 +48,11 @@ def load_node(node_data: dict, node_tree: bpy.types.ShaderNodeTree): node_tree_uuid = node_data.get('node_tree_uuid', None) if image_uuid and not target_node.image: - target_node.image = get_datablock_from_uuid(image_uuid, None) + image = resolve_datablock_from_uuid(image_uuid, bpy.data.images) + if image is None: + logging.error(f"Fail to find material image from uuid {image_uuid}") + else: + target_node.image = image if node_tree_uuid: target_node.node_tree = get_datablock_from_uuid(node_tree_uuid, None) diff --git a/multi_user/bl_types/bl_texture.py b/multi_user/bl_types/bl_texture.py index 62505d5..d839878 100644 --- a/multi_user/bl_types/bl_texture.py +++ b/multi_user/bl_types/bl_texture.py @@ -91,5 +91,10 @@ class BlTexture(ReplicatedDatablock): return deps -_type = [T.WoodTexture, T.WoodTexture, T.StucciTexture, T.NoiseTexture, T.MusgraveTexture, T.MarbleTexture, T.MagicTexture, T.ImageTexture, T.DistortedNoiseTexture, T.CloudsTexture, T.BlendTexture] +_type = [T.WoodTexture, T.VoronoiTexture, + T.StucciTexture, T.NoiseTexture, + T.MusgraveTexture, T.MarbleTexture, + T.MagicTexture, T.ImageTexture, + T.DistortedNoiseTexture, T.CloudsTexture, + T.BlendTexture] _class = BlTexture diff --git a/multi_user/operators.py b/multi_user/operators.py index 0e05d32..5746d07 100644 --- a/multi_user/operators.py +++ b/multi_user/operators.py @@ -92,6 +92,7 @@ def initialize_session(): node_ref.instance = session.repository.rdp.resolve(node_ref.data) if node_ref.instance is None: node_ref.instance = session.repository.rdp.construct(node_ref.data) + node_ref.instance.uuid = node_ref.uuid # Step 2: Load nodes logging.info("Loading nodes")