Skip to content

plugin

Cinema4DLoader

Bases: LoaderPlugin

Source code in client/ayon_cinema4d/api/plugin.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
class Cinema4DLoader(LoaderPlugin):
    hosts = ["cinema4d"]
    settings_category = "cinema4d"

    def get_name_and_namespace(self, context, name, namespace, doc=None):
        if doc is None:
            doc = lib.active_document()

        product_name = context["product"]["name"]
        folder_name: str = context["folder"]["name"]
        namespace = namespace or lib.get_unique_namespace(
            folder_name,
            prefix="_" if folder_name[0].isdigit() else "",
            suffix="",
            doc=doc,
        )
        name = name or product_name

        return name, namespace

    def remove(self, container):
        """Remove all sub containers"""
        container_node = container["node"]
        for obj in lib.get_objects_from_container(container_node):
            obj.Remove()
        container_node.Remove()
        c4d.EventAdd()

remove(container)

Remove all sub containers

Source code in client/ayon_cinema4d/api/plugin.py
206
207
208
209
210
211
212
def remove(self, container):
    """Remove all sub containers"""
    container_node = container["node"]
    for obj in lib.get_objects_from_container(container_node):
        obj.Remove()
    container_node.Remove()
    c4d.EventAdd()

Cinema4DSingleObjLoader

Bases: Cinema4DLoader, ABC

Base Loader plug-in that manages a single Cinema4D object with a filepath parameter.

Instead of containerizing on a hidden selection object this imprints the node itself as a container.

Source code in client/ayon_cinema4d/api/plugin.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
class Cinema4DSingleObjLoader(Cinema4DLoader, ABC):
    """Base Loader plug-in that manages a single Cinema4D object with a
    filepath parameter.

    Instead of containerizing on a hidden selection object this imprints the
    node itself as a container."""

    @property
    @abstractmethod
    def _node_type_id(self) -> int:
        """The node type id to create and manage."""
        pass

    @property
    @abstractmethod
    def _filepath_attribute(self) -> "Union[int, Tuple[int, int]]":
        """Return the id for the filepath attribute on the node type.

        This is usually an `int` constant, but for some nodes like Redshift
        Proxies these are a tuple of two ids.

        """
        pass

    def set_obj_for_context(self, obj, context, is_update=False):
        """Update the object for the new context. This will be called on load
        and update to configure the object for the new context, like setting
        the filepath.

        This can be inherited on child classes to do additional things on load
        or update.

        Arguments:
            obj (c4d.BaseObject): The managed object.
            context (dict[str, Any]): The full representation context.
            is_update (bool): Whether this is part of an `update` call or
                first `load`.

        """
        filepath = self.filepath_from_context(context)
        obj[self._filepath_attribute] = filepath

    def load(self, context, name=None, namespace=None, options=None):

        doc = lib.active_document()

        name, namespace = self.get_name_and_namespace(
            context, name, namespace, doc=doc)

        # Create object
        obj = c4d.BaseObject(self._node_type_id)
        obj.SetName(name)
        doc.InsertObject(obj)

        self.set_obj_for_context(obj, context)

        container = pipeline.imprint_container(
            obj,
            name=str(name),
            namespace=str(namespace),
            context=context,
            loader=str(self.__class__.__name__),
        )

        c4d.EventAdd()

        return container

    def update(self, container, context):

        obj = container["node"]

        # Update filepath
        if obj.CheckType(self._node_type_id):
            self.set_obj_for_context(obj, context)

        # Update representation id
        for i, base_container in obj.GetUserDataContainer():
            if base_container[c4d.DESC_NAME] == "representation":
                obj[i] = context["representation"]["id"]

        c4d.EventAdd()

    def remove(self, container):
        """Remove all sub containers"""
        container_node = container["node"]
        container_node.Remove()
        c4d.EventAdd()

remove(container)

Remove all sub containers

Source code in client/ayon_cinema4d/api/plugin.py
298
299
300
301
302
def remove(self, container):
    """Remove all sub containers"""
    container_node = container["node"]
    container_node.Remove()
    c4d.EventAdd()

set_obj_for_context(obj, context, is_update=False)

Update the object for the new context. This will be called on load and update to configure the object for the new context, like setting the filepath.

This can be inherited on child classes to do additional things on load or update.

Parameters:

Name Type Description Default
obj BaseObject

The managed object.

required
context dict[str, Any]

The full representation context.

required
is_update bool

Whether this is part of an update call or first load.

False
Source code in client/ayon_cinema4d/api/plugin.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def set_obj_for_context(self, obj, context, is_update=False):
    """Update the object for the new context. This will be called on load
    and update to configure the object for the new context, like setting
    the filepath.

    This can be inherited on child classes to do additional things on load
    or update.

    Arguments:
        obj (c4d.BaseObject): The managed object.
        context (dict[str, Any]): The full representation context.
        is_update (bool): Whether this is part of an `update` call or
            first `load`.

    """
    filepath = self.filepath_from_context(context)
    obj[self._filepath_attribute] = filepath

cache_instance_data(shared_data)

Cache instances for Creators shared data.

Create cinema4d_cached_instances key when needed in shared data and fill it with all collected instances from the scene under its respective creator identifiers.

Parameters:

Name Type Description Default
shared_data(Dict[str, Any]

Shared data.

required
Source code in client/ayon_cinema4d/api/plugin.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def cache_instance_data(shared_data):
    """Cache instances for Creators shared data.

    Create `cinema4d_cached_instances` key when needed in shared data and
    fill it with all collected instances from the scene under its
    respective creator identifiers.

    Args:
        shared_data(Dict[str, Any]): Shared data.

    """
    if shared_data.get('cinema4d_cached_instances') is None:
        cache = {}
        doc = lib.active_document()
        for creator_id, obj in iter_instance_objects(doc):
            cache.setdefault(creator_id, []).append(obj)

        shared_data["cinema4d_cached_instances"] = cache

    return shared_data