示例#1
0
    def _diff(self, struct: T.Object, key: str, prop: T.Property,
              context: Context, diff: StructProxy) -> Optional[Delta]:
        from mixer.blender_data.attributes import diff_attribute

        must_replace = False

        data_datablock = struct.data
        if data_datablock is not None:
            dirty_vertex_groups = data_datablock.mixer_uuid in context.visit_state.dirty_vertex_groups
            # Replace the whole Object. Otherwise we would have to merge a DeltaReplace for vertex_groups
            # and a DeltaUpdate for the remaining items
            logger.debug(f"_diff: {struct} dirty vertex group: replace")
            must_replace |= dirty_vertex_groups

        if not must_replace:
            # Parenting with ctrl-P generates a Delta with parent, local_matrix and matrix_parent_inverse.
            # Applying this delta causes a position shift in the parented object. A full replace fixes the problem.
            # Not that parenting with just updating the parent property in the property panel does not cause
            # the same problem
            parent_property = struct.bl_rna.properties["parent"]
            parent_delta = diff_attribute(struct.parent, "parent",
                                          parent_property,
                                          self._data["parent"], context)
            must_replace |= parent_delta is not None

        if must_replace:
            diff.load(struct, context)
            return DeltaReplace(diff)
        else:
            return super()._diff(struct, key, prop, context, diff)
示例#2
0
    def load(
        self,
        bl_collection: T.bpy_prop_collection,
        key: Union[int, str],
        bl_collection_property: T.Property,
        context: Context,
    ):

        if len(bl_collection) == 0:
            self._data.clear()
            return self

        try:
            context.visit_state.path.append(key)
            # no keys means it is a sequence. However bl_collection.items() returns [(index, item)...]
            is_sequence = not bl_collection.keys()
            if is_sequence:
                # easier for the encoder to always have a dict
                self._data = {
                    MIXER_SEQUENCE: [
                        StructProxy.make(v).load(v, i, context) for i, v in enumerate(bl_collection.values())
                    ]
                }
            else:
                self._data = {k: StructProxy().load(v, k, context) for k, v in bl_collection.items()}
        finally:
            context.visit_state.path.pop()
        return self
示例#3
0
def pre_save_struct(proxy: StructProxy, target: T.bpy_struct,
                    context: Context) -> T.bpy_struct:
    """Process attributes that must be saved first"""
    if isinstance(target, T.ColorManagedViewSettings):
        use_curve_mapping = proxy.data("use_curve_mapping")
        if use_curve_mapping:
            target.use_curve_mapping = True
    return target
def _proxy_factory(attr):
    if isinstance(attr, T.ID) and not attr.is_embedded_data:
        from mixer.blender_data.datablock_ref_proxy import DatablockRefProxy

        return DatablockRefProxy()
    elif attr is None:
        from mixer.blender_data.misc_proxies import NonePtrProxy

        return NonePtrProxy()
    else:
        return StructProxy()
示例#5
0
    def load(
        self,
        bl_collection: T.bpy_prop_collection,
        key: Union[int, str],
        bl_collection_property: T.Property,
        context: Context,
    ):

        context.visit_state.path.append(key)
        try:
            self._sequence = [
                StructProxy.make(v).load(v, i, context)
                for i, v in enumerate(bl_collection.values())
            ]
        finally:
            context.visit_state.path.pop()
        return self
示例#6
0
    def test_non_existing(self):
        # test_end_to_end.TestWorld.test_non_existing
        world = bpy.data.worlds[0]

        self.diff.diff(self.bpy_data_proxy, safe_properties)
        sent_ids = {}
        sent_ids.update({("worlds", world.name): world})

        changeset = self.bpy_data_proxy.update(self.diff, {}, False,
                                               safe_properties)
        creations = changeset.creations
        # avoid clash on restore
        world.name = world.name + "_bak"

        codec = Codec()
        for update in creations:
            key = (update.collection_name, update.data("name"))
            sent_id = sent_ids.get(key)
            if sent_id is None:
                continue

            # pretend it is a new one
            update._datablock_uuid += "_new"

            # create a property on the send proxy and test that is does not fail on the receiver
            # property on ID
            update._data["does_not_exist_property"] = ""
            update._data["does_not_exist_struct"] = StructProxy()
            update._data["does_not_exist_ID"] = DatablockProxy()

            encoded = codec.encode(update)
            # sender side
            #######################
            # receiver side
            decoded = codec.decode(encoded)
            created, _ = self.bpy_data_proxy.create_datablock(decoded)
            self.assertEqual(created, sent_id)
示例#7
0
文件: proxy.py 项目: OpenWRLD/mixer
 def deep_wrap(cls, proxy: StructProxy) -> DeltaUpdate:
     """Recursively wraps proxy members in DeltaUpdate items."""
     p = proxy.__class__()
     for k, v in proxy._data.items():
         p.data[k] = DeltaUpdate.deep_wrap(v)
     return cls(p)
示例#8
0
def read_attribute(attr: Any, key: Union[int, str], attr_property: T.Property,
                   context: Context):
    """
    Load a property into a python object of the appropriate type, be it a Proxy or a native python object
    """
    attr_type = type(attr)

    if is_builtin(attr_type):
        return attr
    if is_vector(attr_type):
        return list(attr)
    if is_matrix(attr_type):
        return [list(col) for col in attr.col]

    # We have tested the types that are usefully reported by the python binding, now harder work.
    # These were implemented first and may be better implemented with the bl_rna property of the parent struct
    # TODO flatten
    if attr_type == T.bpy_prop_array:
        return list(attr)

    try:
        context.visit_state.recursion_guard.push(attr_property.identifier)
        if attr_type == T.bpy_prop_collection:
            if isinstance(attr_property.fixed_type, bpy.types.ID):
                from mixer.blender_data.datablock_collection_proxy import DatablockRefCollectionProxy

                return DatablockRefCollectionProxy().load(attr, key, context)
            elif is_soable_collection(attr_property):
                from mixer.blender_data.aos_proxy import AosProxy

                return AosProxy().load(attr, key, attr_property, context)
            else:
                from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

                return StructCollectionProxy.make(attr_property).load(
                    attr, key, attr_property, context)

        # TODO merge with previous case
        if isinstance(attr_property, T.CollectionProperty):
            from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

            return StructCollectionProxy().load(attr, key, attr_property,
                                                context)

        bl_rna = attr_property.bl_rna
        if bl_rna is None:
            logger.warning("Not implemented: attribute %s", attr)
            return None

        if issubclass(attr_type, T.PropertyGroup):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy().load(attr, key, context)

        if issubclass(attr_type, T.ID):
            if attr.is_embedded_data:
                from mixer.blender_data.datablock_proxy import DatablockProxy

                return DatablockProxy.make(attr_property).load(
                    attr, key, context)
            else:
                from mixer.blender_data.datablock_ref_proxy import DatablockRefProxy

                return DatablockRefProxy().load(attr, key, context)

        if issubclass(attr_type, T.bpy_struct):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy().load(attr, key, context)

        if attr is None and isinstance(attr_property, T.PointerProperty):
            from mixer.blender_data.misc_proxies import NonePtrProxy

            return NonePtrProxy()

        logger.error(
            f"Unsupported attribute {attr_type} {attr_property} {attr_property.fixed_type} at {context.visit_state.datablock_proxy._class_name}.{context.visit_state.path}.{attr_property.identifier}"
        )
    finally:
        context.visit_state.recursion_guard.pop()
示例#9
0
def read_attribute(attr: Any, key: Union[int, str], attr_property: T.Property,
                   parent: T.bpy_struct, context: Context):
    """
    Load a property into a python object of the appropriate type, be it a Proxy or a native python object
    """

    try:
        return _read_builtin(attr)
    except _NotBuiltin:
        pass

    if isinstance(attr, set):
        from mixer.blender_data.misc_proxies import SetProxy

        return SetProxy().load(attr)

    context.visit_state.push(attr_property, key)
    try:
        from mixer.blender_data.misc_proxies import PtrToCollectionItemProxy

        attr_type = type(attr)
        if attr_type == T.bpy_prop_collection:
            if hasattr(attr, "bl_rna") and isinstance(
                    attr.bl_rna, (type(T.CollectionObjects.bl_rna),
                                  type(T.CollectionChildren.bl_rna))):
                from mixer.blender_data.datablock_collection_proxy import DatablockRefCollectionProxy

                return DatablockRefCollectionProxy().load(attr, context)
            elif is_soable_collection(attr_property):
                from mixer.blender_data.aos_proxy import AosProxy

                return AosProxy().load(attr, attr_property, context)
            else:
                # This code path is taken for collections that have an rna and collections that do not
                # There should probably be different proxies for collection with and without rna.
                # See comment in add_element()
                from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

                return StructCollectionProxy.make(attr_property).load(
                    attr, context)

        # TODO merge with previous case
        if isinstance(attr_property, T.CollectionProperty):
            from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

            return StructCollectionProxy().load(attr, context)

        bl_rna = attr_property.bl_rna
        if bl_rna is None:
            logger.error("read_attribute: no implementation for ...")
            logger.error(
                f"... {context.visit_state.display_path()}.{key} (type: {type(attr)})"
            )
            return None

        if issubclass(attr_type, T.PropertyGroup):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy.make(attr).load(attr, context)

        if issubclass(attr_type, T.ID):
            if attr.is_embedded_data:
                # Embedded datablocks are loaded as StructProxy and DatablockProxy is reserved
                # for standalone datablocks
                from mixer.blender_data.struct_proxy import StructProxy

                return StructProxy.make(attr).load(attr, context)
            else:
                # Standalone databocks are loaded from DatablockCollectionProxy, so we can only encounter
                # datablock references here
                from mixer.blender_data.datablock_ref_proxy import DatablockRefProxy

                return DatablockRefProxy().load(attr, context)

        proxy = PtrToCollectionItemProxy.make(type(parent), key)
        if proxy is not None:
            return proxy.load(attr)

        if issubclass(attr_type, T.bpy_struct):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy.make(attr).load(attr, context)

        if attr is None:
            from mixer.blender_data.misc_proxies import NonePtrProxy

            return NonePtrProxy()

        logger.error("read_attribute: no implementation for ...")
        logger.error(
            f"... {context.visit_state.display_path()}.{key} (type: {type(attr)})"
        )
    finally:
        context.visit_state.pop()
示例#10
0
def read_attribute(attr: Any, key: Union[int, str], attr_property: T.Property,
                   context: Context):
    """
    Load a property into a python object of the appropriate type, be it a Proxy or a native python object
    """

    if isinstance(attr, _builtin_types):
        return attr

    attr_type = type(attr)
    if is_vector(attr_type):
        return list(attr)
    if is_matrix(attr_type):
        return [list(col) for col in attr.col]
    if isinstance(attr, set):
        from mixer.blender_data.misc_proxies import SetProxy

        return SetProxy().load(attr)

    # We have tested the types that are usefully reported by the python binding, now harder work.
    # These were implemented first and may be better implemented with the bl_rna property of the parent struct
    # TODO flatten
    if attr_type == T.bpy_prop_array:
        return list(attr)

    context.visit_state.recursion_guard.push(attr_property.identifier)
    try:
        from mixer.blender_data.misc_proxies import PtrToCollectionItemProxy

        if attr_type == T.bpy_prop_collection:
            if hasattr(attr, "bl_rna") and isinstance(
                    attr.bl_rna, (type(T.CollectionObjects.bl_rna),
                                  type(T.CollectionChildren.bl_rna))):
                from mixer.blender_data.datablock_collection_proxy import DatablockRefCollectionProxy

                return DatablockRefCollectionProxy().load(attr, key, context)
            elif is_soable_collection(attr_property):
                from mixer.blender_data.aos_proxy import AosProxy

                return AosProxy().load(attr, key, attr_property, context)
            else:
                from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

                return StructCollectionProxy.make(attr_property).load(
                    attr, key, attr_property, context)

        # TODO merge with previous case
        if isinstance(attr_property, T.CollectionProperty):
            from mixer.blender_data.struct_collection_proxy import StructCollectionProxy

            return StructCollectionProxy().load(attr, key, attr_property,
                                                context)

        bl_rna = attr_property.bl_rna
        if bl_rna is None:
            logger.error("read_attribute: no implementation for ...")
            logger.error(
                f"... {context.visit_state.display_path()}.{key} (type: {type(attr)})"
            )
            return None

        if issubclass(attr_type, T.PropertyGroup):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy().load(attr, key, context)

        if issubclass(attr_type, T.ID):
            if attr.is_embedded_data:
                # Embedded datablocks are loaded as StructProxy and DatablockProxy is reserved
                # for standalone datablocks
                from mixer.blender_data.struct_proxy import StructProxy

                return StructProxy().load(attr, key, context)
            else:
                # Standalone databocks are loaded from DatablockCollectionProxy, so we can only encounter
                # datablock references here
                from mixer.blender_data.datablock_ref_proxy import DatablockRefProxy

                return DatablockRefProxy().load(attr, key, context)

        proxy = PtrToCollectionItemProxy.make(attr_type, key)
        if proxy:
            return proxy.load(attr)

        if issubclass(attr_type, T.bpy_struct):
            from mixer.blender_data.struct_proxy import StructProxy

            return StructProxy().load(attr, key, context)

        if attr is None:
            from mixer.blender_data.misc_proxies import NonePtrProxy

            return NonePtrProxy()

        logger.error("read_attribute: no implementation for ...")
        logger.error(
            f"... {context.visit_state.display_path()}.{key} (type: {type(attr)})"
        )
    finally:
        context.visit_state.recursion_guard.pop()
示例#11
0
 def test_skip_ShaderNodeTree(self):  # noqa N802
     world = D.worlds["World"]
     proxy = StructProxy().load(world, self._context)
     self.assertTrue("color" in proxy._data)