The Maxon SDK Team is currently short staffed due to the winter holidays. No forum support is being provided between 15/12/2025 and 5/1/2026. For details see Maxon SDK 2025 Winter Holidays.
  • Traversing Asset Categories

    python 2023
    3
    0 Votes
    3 Posts
    725 Views
    ferdinandF
    Hello @d_keith, Thank you for reaching out to us. So, I had a look, and I could not find a bug with ExpandAssetCategoryId. I tried built-in categories, custom categories, and custom categories inside a custom database. My traversal method does return everything what I would expect to be returned. Find a more elaborate variant of ExpandAssetCategoryId below (I turned it into a class for easier inspection of the data). There are a few things which could go wrong here: You misunderstood the purpose of ExpandAssetCategoryId, it expands a category tree in a top-down fashion. E.g., for A->B->C, ExpandAssetCategoryId(B) will yield B, C but not A. It could certainly be done differently but that would be up to you. There is a bug in your code in another place. There might exist special conditions in the environment you are working in, but that is nothing for the forum. Find below my example which will expand asset category trees from a root in a more visual and therefore easier to check manner. Cheers, Ferdinand The result: -------------------------------------------------------------------------------- AssetCategoryHandler at 0X7FD2F3350B90 (repo = database@U1pOb6rnHdar41NpWahfnn): Managed IDs: (maxon.Id('category@3d2621c1bc48485aa2b7ceead989e421'), maxon.Id('category_32a5e2eefcc10592'), maxon.Id('category_3e39b2c258ae9313'), maxon.Id('category_f7cb610b3f172a93'), maxon.Id('category_8f51f303e1bbf875'), maxon.Id('category_bb4c48de0af7b8b3'), maxon.Id('category_28801c2ab359e01e'), maxon.Id('category_fd68f940d0b615ab'), maxon.Id('category_993d6d73f3c2629e'), maxon.Id('category_fce5f1171ae19de7'), maxon.Id('category_50bbe4f91e99090b'), maxon.Id('category_074c78c3e2d70ab9'), maxon.Id('category_c92b8c257f9e7517'), maxon.Id('category@23efef776140438f80b9ca1b0eef53f7'), maxon.Id('category_a800e5a243f9f385'), maxon.Id('category_9676f914364e4e27'), maxon.Id('category_e024f65cd280795e'), maxon.Id('category_2ab08ca489795a07'), maxon.Id('category_c04b37955dcb3895'), maxon.Id('category_34ed541e2020f38e'), maxon.Id('category_f7316fed1fc11137'), maxon.Id('category_efb8eae1116900c2'), maxon.Id('category_c0e06630879697c2'), maxon.Id('category_f4afa4f900193b95'), maxon.Id('category_476ff23d55425ca4'), maxon.Id('category_58e6a054402a25fd'), maxon.Id('category_ddcdf72383424d7e'), maxon.Id('category_ca1600eb107c6082'), maxon.Id('category_1b0948c77cb2f61e'), maxon.Id('category@c19d76abc1bf46f296ed837fd9e8a215'), maxon.Id('category_f40806b20b84f759'), maxon.Id('category_8ea059e3d503175a'), maxon.Id('category_9147f39c273d8342'), maxon.Id('category@6608dc0e700442f196c788a53170a078'), maxon.Id('category@d8567d0c206145979ef94bf495128c00'), maxon.Id('category@1bc8d3a8b3764acfb82bf5409646fe9f'), maxon.Id('category@8b5f3e8dfbb2489caff67db176800a50'), maxon.Id('category@d1b7bff693344889aa2b98b2f77e80ac'), maxon.Id('category@edad962d94254a26a90a492fae589221'), maxon.Id('category@7cd25e2b9d5c408986cded4f33d59c47'), maxon.Id('category@ed2c2d5352cc461389526a4d9006febc'), maxon.Id('category@5daaf21dde924b7abf18a25256282b69'), maxon.Id('category@338d4b421ddb4ac1a1d7df21c0376911'), maxon.Id('category@c0455a450d0e40eba0c09ad0673d876a'), maxon.Id('category@88057ec2780148708363b96272234ded'), maxon.Id('category@9d1a886ec1584d9f8794c59187c3d3d1'), maxon.Id('category@cec99ab7a44f4b0bac4cedd538f44e02'), maxon.Id('category@13549430f6a54bee9562d3541cb85614'), maxon.Id('category@323d8d63b88b4ab4ba5bed368d895048'), maxon.Id('category@a28830367831413f9fa5b66e4a5dd65f'), maxon.Id('category@94fc8cb5718a492d9fd34f907b89720d'), maxon.Id('category@bae2bf9f00d949c7b5df05cd6cba7966'), maxon.Id('category_bb2ed911f3303be2'), maxon.Id('category_4c6f230c27d35ad7'), maxon.Id('category_e2204ff5b9252604'), maxon.Id('category_0359297d725f327a'), maxon.Id('category_4cc30dbe0f38a155'), maxon.Id('category_1fee6083977acfee'), maxon.Id('category_5904e55a542a55eb'), maxon.Id('category@3448f9feaed44cedac87d499a4567a26'), maxon.Id('category_248c7a50c5c70f4c'), maxon.Id('category_8509ac933bece593'), maxon.Id('category@3be598900c7a428eb0fcbced997655ba'), maxon.Id('category_64f67f3727141f1a'), maxon.Id('category@e33ef358a9b24d6cab80454a4179e419'), maxon.Id('category_63ebef6aab44bd4d'), maxon.Id('category_045526cd4a11b6dc'), maxon.Id('category@a91d4cacaeba4170bf0c202d583fe2e0'), maxon.Id('category@35ee4e3871414784a3767fc2037c305b'), maxon.Id('category_04cdfd3b558329b6'), maxon.Id('category_24b5ae0d89e20ccc'), maxon.Id('category_cd5ad0a08c825d60'), maxon.Id('category_1c643f453b71129e'), maxon.Id('category_f9bd2fcc800c8279'), maxon.Id('category_468266206e683e39'), maxon.Id('category_172e168c2640e535'), maxon.Id('category@c9f25306ba024d939ae97d0999d70995'), maxon.Id('category_ab975c5373b7ba07'), maxon.Id('category@5e2b516fbc0541ad9d59781d675ad8f9'), maxon.Id('category_0133f046d03a46e7'), maxon.Id('category_74ec3ae6ecaab0de'), maxon.Id('category_fcf83cd1ff7e0fea'), maxon.Id('category_32750a41ff5ae804'), maxon.Id('category_f3dfa1fc22e1760f'), maxon.Id('category_8c28445d28cba3b6'), maxon.Id('category_65263c7c1c8c423c'), maxon.Id('category_67a056c194d9897c'), maxon.Id('category_73d82da307ebac4f'), maxon.Id('category_fa850c478d745f9e'), maxon.Id('category@780d427523e243028086a1aa33745b66'), maxon.Id('category_8cbecf2e6c1c53e6'), maxon.Id('category_66c6a982b7227e77'), maxon.Id('category_a2fde34845c656bd'), maxon.Id('category_95b2c4bc77dbeb2d'), maxon.Id('category@f7ac3097518e4141a80ec19bc0c8548b'), maxon.Id('category@93c3e0df81e54acfae70a129ad8f7fc0'), maxon.Id('category@9812f958facf4bc39d90fb79cc4fe783'), maxon.Id('category_ecfd5ef0b32fdc6e'), maxon.Id('category@4d87bd4452b8493aa2ffd9e9500cba56'), maxon.Id('category_de343673ae7ff879'), maxon.Id('category_2aa95f92d383989e'), maxon.Id('category_aded6c15b065a4a5'), maxon.Id('category_fe8c8340d4cfebef'), maxon.Id('category_2d90a72a03048a0a'), maxon.Id('category_8191022b0575a8c8'), maxon.Id('category_94bc6daab0db3454'), maxon.Id('category@7f080054d14f4758aefb36dfae705b88'), maxon.Id('category@d7bd914db4194b13baebbb49f981f395'), maxon.Id('category_bdac9c772d258396'), maxon.Id('category@ee5c708a346740a591544bb9be87cf8d'), maxon.Id('category_f72dcc94be532fa4'), maxon.Id('category_d6e2d304d1c0eb76'), maxon.Id('category_819c3f327c46106c'), maxon.Id('category_a7dd93c148997ea2'), maxon.Id('category_adbf1096d2400c47'), maxon.Id('category_6bf21b118e626b8f'), maxon.Id('category_66478df5e0c296b2'), maxon.Id('category_5ff49c9a181cad8c'), maxon.Id('category_06eaa38e9750e5e3'), maxon.Id('category_732f5bf076c873c7'), maxon.Id('category_781d1c68184a4319'), maxon.Id('category_b6d6fd4c864f01d8'), maxon.Id('category_bcc53614ed7486b6'), maxon.Id('category_20a0233895be23f3'), maxon.Id('category_d42b5d6450873989'), maxon.Id('category_cea3e864eb47b596'), maxon.Id('category_3385066daeaf9819'), maxon.Id('category@1445293c87e64c7684011d9c0477754e'), maxon.Id('category@1f03b25c815e421789036e5a84a3ccf1'), maxon.Id('category@9a2779a603bc4e1f93b9577abe5ecad1'), maxon.Id('category@3064bcb4ff4e4ae890730837caea6f10'), maxon.Id('category@1ba9498066ff42b6b2916242f8d8e7bb'), maxon.Id('category@ef89ec1e9b5a47a5b245e05c5c8b1418'), maxon.Id('category@b674f3ffaa9247f390fdbd49a08111a7'), maxon.Id('category@9a75f45dc5984049b0307b5dc1aea91e'), maxon.Id('category_ef962b4216a17f64'), maxon.Id('category_5a9141a0036aa0e2'), maxon.Id('category_e682fa27d7eb619d'), maxon.Id('category_899783790d811f25'), maxon.Id('category@beb1c0ee13d948faa8e2b084e6b23ab6')) Tree: '/Objects' '/Objects/Info Graphics' '/Objects/Humans' '/Objects/Humans/3D Posable Silhouettes' '/Objects/Humans/3D People - For Animation' '/Objects/Humans/3D People [Low Resolution]' '/Objects/Humans/3D People [Medium Resolution]' '/Objects/Humans/Cutout' '/Objects/Packaging' '/Objects/Tools' '/Objects/Vehicles' '/Objects/Periodicals' '/Objects/Appliances' '/Objects/Eyewear' '/Objects/Garments' '/Objects/Finance' '/Objects/Plants' '/Objects/Plants/European Trees Young' '/Objects/Plants/Garden & Exotic' '/Objects/Plants/European Trees Mature' '/Objects/Plants/Houseplants' '/Objects/Plants/Cutouts' '/Objects/Plants/Grass Elements' '/Objects/Plants/Grass Elements/Low Resolution' '/Objects/Plants/Grass Elements/Medium Resolution' '/Objects/Pots' '/Objects/Shelving' '/Objects/Shelving/Modular Cabinets & Doors' '/Objects/Shelving/Modular Cabinets & Doors/Misc Cabinet Examples' '/Objects/Shelving/Modular Cabinets & Doors/Cabinet & Door Pieces' '/Objects/Shelving/Modular Cabinets & Doors/Misc Door Examples' '/Objects/Shelving/Living Room & Bedroom' '/Objects/Celebration' '/Objects/Kitbash' '/Objects/Kitbash/Piping' '/Objects/Kitbash/Piping/Corners' '/Objects/Kitbash/Piping/Pipes' '/Objects/Kitbash/Piping/Pipe' '/Objects/Kitbash/Details' '/Objects/Kitbash/Details/Squares' '/Objects/Kitbash/Details/Crosses' '/Objects/Kitbash/Details/Geometric' '/Objects/Kitbash/Details/Triangles' '/Objects/Kitbash/Details/Hexagons' '/Objects/Kitbash/Details/Arrows' '/Objects/Kitbash/Details/Rectangles' '/Objects/Kitbash/Details/Circles' '/Objects/Kitbash/Details/Pattern' '/Objects/Kitbash/Tubes' '/Objects/Kitbash/Connectors' '/Objects/Kitbash/Joints' '/Objects/Toys' '/Objects/Outdoor Objects' '/Objects/Outdoor Objects/Scaffolds' '/Objects/Outdoor Objects/Trash Cans' '/Objects/Outdoor Objects/Buildings' '/Objects/Outdoor Objects/Buildings/Houses' '/Objects/Outdoor Objects/Buildings/Cityscape' '/Objects/Outdoor Objects/Buildings/Misc' '/Objects/Outdoor Objects/Wall Decor' '/Objects/Outdoor Objects/Manholes' '/Objects/Outdoor Objects/Miscellaneous' '/Objects/Outdoor Objects/Traffic Lights' '/Objects/Outdoor Objects/Antennas' '/Objects/Outdoor Objects/Pavement' '/Objects/Outdoor Objects/Street Lights' '/Objects/Outdoor Objects/Bus Stops' '/Objects/Outdoor Objects/Fire Escapes' '/Objects/Outdoor Objects/Infrastructure' '/Objects/Outdoor Objects/Road Signs' '/Objects/Outdoor Objects/Barriers & Barricades' '/Objects/Tables' '/Objects/Tables/Bedside Tables' '/Objects/Tables/Game Tables' '/Objects/Tables/Office Tables' '/Objects/Tables/Coffee Tables' '/Objects/Tables/Dining Tables' '/Objects/Arts & Crafts' '/Objects/Stairs' '/Objects/Cogwheel Objects' '/Objects/Cogwheel Objects/Saws' '/Objects/Cogwheel Objects/Gears' '/Objects/Cogwheel Objects/Miscellaneous' '/Objects/Cogwheel Objects/Clutches' '/Objects/Cogwheel Objects/Ratchet' '/Objects/Cogwheel Objects/Watch Gears' '/Objects/Kitchen' '/Objects/Kitchen/Cutlery' '/Objects/Kitchen/Dinnerware' '/Objects/Kitchen/Accessories' '/Objects/Kitchen/Cookware' '/Objects/Kitchen/Serveware' '/Objects/Kitchen/Glassware' '/Objects/Screws' '/Objects/Landscape' '/Objects/Landscape/Wood' '/Objects/Landscape/Stones' '/Objects/Vases' '/Objects/Window Treatments' '/Objects/Seating' '/Objects/Seating/Sofas' '/Objects/Seating/Waiting Areas' '/Objects/Seating/Benches' '/Objects/Seating/Chairs' '/Objects/Lighting & Ceiling Fans' '/Objects/Lighting & Ceiling Fans/Ceiling Lighting' '/Objects/Lighting & Ceiling Fans/Home Safety & Security' '/Objects/Lighting & Ceiling Fans/Outdoor Lighting' '/Objects/Lighting & Ceiling Fans/Wall Lighting' '/Objects/Lighting & Ceiling Fans/Ceiling Fans' '/Objects/Lighting & Ceiling Fans/Lamps' '/Objects/Lighting & Ceiling Fans/Light Bulbs' '/Objects/Lighting & Ceiling Fans/Light Stands' '/Objects/Music' '/Objects/Bedroom' '/Objects/Bath' '/Objects/Bath/Toilets' '/Objects/Bath/Bathroom Vanities' '/Objects/Bath/Sinks' '/Objects/Bath/Towels' '/Objects/Bath/Bathroom Accessories' '/Objects/Bath/Bathtubs & Showers' '/Objects/Bath/Faucets' '/Objects/Gambling' '/Objects/Stationary' '/Objects/Sculpting Base Meshes' '/Objects/Weather' '/Objects/Home Decor' '/Objects/Home Decor/Candles' '/Objects/Home Decor/Books' '/Objects/Home Decor/Picture Frames' '/Objects/Home Decor/Decorative Storage' '/Objects/Home Decor/Candleholders' '/Objects/Home Decor/Decorative Boxes' '/Objects/Home Decor/Clocks' '/Objects/Electronics & Technology' '/Objects/Miscellaneous' '/Objects/Sports Items' '/Objects/Food' '/Objects/Doors & Windows' -------------------------------------------------------------------------------- AssetCategoryHandler at 0X7FD2F3368910 (repo = net.maxon.repository.userprefs): Managed IDs: (maxon.Id('category@0ad833e88d774ac1ae4fd277e57ecacc'), maxon.Id('category@d8bc777f959e48bda659d1674bb1d5f3'), maxon.Id('category@0399404fe6fc46558b8f98f63d49ce28'), maxon.Id('category@08ab3faa66e348fe86574469cbabb2c7'), maxon.Id('category@793e20a462f04c64a5cea28209f9a38b')) Tree: '/MyUserCategory' '/MyUserCategory/Blah' '/MyUserCategory/Blah/Blub' '/MyUserCategory/Blub' '/MyUserCategory/Blub/Blah' -------------------------------------------------------------------------------- AssetCategoryHandler at 0X7FD2F1CBED10 (repo = database@CGBLAN4TBpzrDfyA9gjMTn): Managed IDs: (maxon.Id('category@d1233ed9975945debc8942a30edfd706'), maxon.Id('category@cfce060493cd4c61b92a115624d33eb1'), maxon.Id('category@fa80f5a53cea42b7a72f494f0d673377'), maxon.Id('category@ae9c2c99dee74deeb8a7a7d711d57ffe'), maxon.Id('category@ffc383ed61454affa841f13931f93125')) Tree: '/AlsoUserCategory' '/AlsoUserCategory/Foo' '/AlsoUserCategory/Foo/Bar' '/AlsoUserCategory/Blah' '/AlsoUserCategory/Blah/Blub' The code: """Provides a type to expand asset categories into trees. """ import c4d import maxon import typing import pprint class AssetCategoryHandler: """Handles an asset category that is a root to zero to many descendant categories. """ def __init__(self, asset: maxon.AssetDescription, categories: list[maxon.AssetDescription] = [], language: maxon.LanguageRef = maxon.Resource.GetCurrentLanguage(), path: str = ""): """Initializes the handler. Args: asset (maxon.AssetDescription): The category asset to expand. categories (list[maxon.AssetDescription], optional): A list of categories which should be respected for expansion, when the empty list is passed, the assets will be gathered from the repository #asset is attached to. Defaults to []. language (maxon.LanguageRef, optional): The language to retrieve asset strings in. Defaults to maxon.Resource.GetCurrentLanguage(). path (str, optional): [internal] The current parent path. Defaults to "". Raises: TypeError: On type assertion failures. """ # Type checks and retrieving some data from the asset. if not isinstance(asset, maxon.AssetDescription) or asset.IsNullValue(): raise TypeError(f"{asset = }") if not isinstance(categories, list): raise TypeError(f"{categories = }") if not isinstance(language, maxon.LanguageRef) or language.IsNullValue(): raise TypeError(f"{language = }") self._asset: maxon.AssetDescription = asset self._aid: maxon.Id = maxon.Id(asset.GetId()) if isinstance(asset.GetId(), str) else asset.GetId() self._name: str = asset.GetMetaString(maxon.OBJECT.BASE.NAME, language, "") self._path: str = f"{path}/{self._name}" self._repo: maxon.AssetRepositoryRef = asset.GetRepository() self._categories: list[maxon.AssetDescription] = categories self._language: maxon.LanguageRef = language self._children: list["AssetCategoryHandler"] = [] # Populate _categories when empty. if len(self._categories) < 1: self._categories = self._repo.FindAssets( maxon.AssetTypes.Category(), maxon.Id(),maxon.Id(), maxon.ASSET_FIND_MODE.LATEST) # Expand the tree and cache the IDs. self.__expand__() self._ids: tuple[maxon.Id] = tuple(self.__yieldids__()) def __repr__(self) -> str: """Returns a string representation of the handler. """ return f"{self.__class__.__name__} at {str(hex(id(self))).upper()}" def __expand__(self): """Expands the handler into a tree of handlers, one for each of the descendant categories of the wrapped category asset. """ for asset in self._categories: if self._aid != maxon.CategoryAssetInterface.GetParentCategory(asset): continue child = AssetCategoryHandler(asset, self._categories, self._language, self._path) self._children.append(child) def __yieldids__(self) -> typing.Generator[maxon.Id, None, None]: """Provides a generator for all asset IDs associated with this handler. Use the property Ids instead, unless rebuilding this data is desired. """ yield self._aid for child in self._children: for aid in child.__yieldids__(): yield aid @property def Ids (self) -> tuple[maxon.Id]: """Returns a tuple of all asset IDs associated with this handler. """ return self._ids def PrintTree(self, indent: int = 0) -> None: """Prints an asset tree for this handler. """ print(f"{' ' * indent}'{self._path}'") for handler in self._children: handler.PrintTree(indent + 1) def main() -> None : """Runs the example. """ # Get the user preferences asset repository, in a production environment it will contain all # relevant assets as of 2023.1.0. if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading(): raise RuntimeError("Could not load asset databases.") repo: maxon.AssetRepositoryInterface = maxon.AssetInterface.GetUserPrefsRepository() if not repo: raise RuntimeError("Unable to retrieve user repository.") # Used to shorten the call signatures of the FindLatestAsset() calls below. kwargs: dict = { "type": maxon.AssetTypes.Category(), "version": maxon.Id(), "findMode": maxon.ASSET_FIND_MODE.LATEST } # Get a couple of root level asset categories. categoryRoots: list[maxon.AssetDescription] = [ # The /Objects category in the Asset Browser, a built-in category. repo.FindLatestAsset(aid=maxon.Id("category@3d2621c1bc48485aa2b7ceead989e421"), **kwargs), # # /Example Scenes # repo.FindLatestAsset(aid= maxon.Id("category@4e785a69ef3749738bfd9d2b191535d5"), **kwargs), # # /Materials # repo.FindLatestAsset(aid= maxon.Id("category_a1ba084a9eeedb9b"), **kwargs), # # /Nodes # repo.FindLatestAsset(aid= maxon.Id("category@52d8f01357834200aa0dc28f0e61bbb3"), **kwargs), # # /Textures # repo.FindLatestAsset(aid= maxon.Id("category@8c76a408c56f4b5ca9f585dbe0ece9b7"), **kwargs), # Custom category trees, they will be filtered out on other machines then mine, since other # machines won't find these assets. # /MyUserCategory (stored in the database in the user prefs) repo.FindLatestAsset(aid= maxon.Id("category@0ad833e88d774ac1ae4fd277e57ecacc"), **kwargs), # /AlsoUserCategory (stored in a custom database) repo.FindLatestAsset(aid= maxon.Id("category@d1233ed9975945debc8942a30edfd706"), **kwargs), ] # Wrap each one of them into a handler. categoryHandlerList: list["AssetCategoryHandler"] = [ AssetCategoryHandler(asset) for asset in categoryRoots if isinstance(asset, maxon.AssetDescription) and not asset.IsNullValue()] # Iterate over the handlers and inspect their data. for handler in categoryHandlerList: print ("\n", "-" * 80) print (f"{handler} (repo = {handler._asset.GetRepositoryId()}):\n") print ("\nManaged IDs:\n") pprint.pprint(handler.Ids) print ("\nTree:\n") handler.PrintTree(indent=1) if __name__ == "__main__": main()
  • Crash when calling TreeViewFunctions::DrawCell

    r23 c++
    4
    2
    0 Votes
    4 Posts
    877 Views
    A
    Hi @m_adam , thanks for your apply. I have solved this problem. The reason is I used maxon::BaseArray to store tree node data. When I append the array, the address of node may change, but the next pointer in node remain unchanged. And this cause the crash.
  • Reset Scale With Compensate Points?

    r25 python
    3
    1
    0 Votes
    3 Posts
    683 Views
    B
    @m_adam Gotcha. Thanks for the response. It works but I was kinda looking for the thought process on how to implement it. Mainly because the command is only limited to scale. I was hoping I can modify it to include also rotation.
  • PYTHONPATH not appended to sys.path in Cinema 4D 24

    s24 python
    6
    0 Votes
    6 Posts
    1k Views
    F
    Excellent! Thanks you a lot Regards,
  • A SetBit problem aka cann't select node.

    python windows
    5
    2
    0 Votes
    5 Posts
    555 Views
    DunhouD
    @ferdinand Thanks for the new solution for SetActiveObject . It works as expected. Much appreciated !
  • C4D Parent constraint python

    python
    14
    0 Votes
    14 Posts
    3k Views
    iplaiI
    @ferdinand Thanks, you are the best. This is exactly the internal operation I'm finding.
  • Mograph Objects Python

    python
    4
    0 Votes
    4 Posts
    716 Views
    ferdinandF
    Hello @joel, Thank you for reaching out to us and thank you @iplai for providing the answer. There is not much to add for us here. Prior to 2023.0.0 there were some larger gaps in the type symbol definitions of classic API nodes, e.g., objects, tags, materials, shaders, Xpresso nodes, scene hooks, etc, because they were never defined in the frameworks (so this was not just a Python thing, even in our internal C++ API they were more or less hardcoded). One major offender was your use case, MoGraph. With 2023.0.0 I have added the cases which I considered most important for public users, objects, materials, shaders, tags and Xpresso nodes. But there are still some gaps in more fringe node types as for example scene hooks, because it is quite a bit of work to pull them out of our code base. With that being said, a type symbol is just that: a symbol. They stand for the integer ID with which the type is being registered. You can always use the raw integer value or just define a symbol for the integer value yourself. import c4d # Define the two symbols yourself and attach them to the c4d module. c4d.Omgcloner: int = 1018544 c4d.Omginheritance: int = 1018775 def main(): """ """ a: c4d.BaseObject = c4d.BaseObject(c4d.Omgcloner) b: c4d.BaseObject = c4d.BaseObject(c4d.Omginheritance) if None in (a, b): raise MemoryError("Object allocation failed.") doc.InsertObject(a) doc.InsertObject(b) c4d.EventAdd() if __name__ == "__main__": main() An uncomplicated way to find out these type symbols is the console and the method C4DAtom.GetType (all classic API nodes are of type C4DAtom). Drag the thing you are interested in into the console (e.g., the Inheritance object) and type after it .GetType() and press Enter: [image: 1668067076009-gettype.gif] Cheers, Ferdinand
  • Get All Assets in Category

    python
    3
    1
    0 Votes
    3 Posts
    936 Views
    ferdinandF
    Hello @d_keith, thank you for reaching out to us and your extensive documentation efforts. Much appreciated! What you did there is correct, but in the spirit of simplicity, I think the code could be a bit condensed. There snuck in a few unused (and unrelated) includes and being so generous with separating things into help functions can impact readability and execution times. I also added the "expand asset category into sub-categories" thing you wanted. In short: I think this is a good occasion to use a receiver callback function, as this structures the code naturally. Find my take below. Cheers, Ferdinand The result: categoryIds = [maxon.Id('category@b9c32d04a12d449ca1c758ddb3c695b0'), maxon.Id('category@985a9913c47341e4a373ca71d8e73b18')] name = 'Cloudy - VHDRI.hdr', asset.GetId() = 'file_e02d0a81b02be4fa' name = 'Default HDR.hdr', asset.GetId() = 'file_2792c7829905f40d' name = 'Desert.exr', asset.GetId() = 'file_0b3eb8e7595c1b5d' name = 'jhdri-v1_ext_sunset_seastar_acescg.exr', asset.GetId() = 'file_dc156adf0cc146e8' name = 'HDR012.hdr', asset.GetId() = 'file_b1db2c38badb130c' The code: """Retrieves all MediaImage assets that are attached to the "Textures/HDR" category or one of its child categories. This is an application of what I dubbed "Filtered Asset searches" in the C++ Docs, find the Python example here [1]. References: [1] https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/scripts/05_modules/assets/asset_databases_r26.py#L416 """ import typing import maxon def ExpandAssetCategoryId(repo: maxon.AssetRepositoryInterface, cid: maxon.Id) -> list[maxon.Id]: """Retrieves the IDs of all descendant asset categories of #cid. """ # Get all asset category assets in #repo. categoryAssets: maxon.AssetDescription = repo.FindAssets( maxon.AssetTypes.Category(), maxon.Id(),maxon.Id(), maxon.ASSET_FIND_MODE.LATEST) # The IDs we have currently to check for descendants and the final result list. idsToCheck: list[maxon.Id] = [cid] results: list[maxon.Id] = [] # Try to empty #idsToCheck while popping elements from it and adding new ones. while idsToCheck: # Remove the first element and add it to the results. cid: maxon.Id = idsToCheck.pop() results.append(cid) # Find all category assets which have #cid as their parent category and add their IDs as # to be resolved category IDs. We stop the search here early, i.e., we assume the category # tree to be mono-hierarchical (one category can only be attached to one category). There # is not really anything in the Asset API which would enforce this, but it is how asset # categories are currently handled. for asset in categoryAssets: if cid == maxon.CategoryAssetInterface.GetParentCategory(asset): aid: typing.Any = asset.GetId() idsToCheck.append(aid if isinstance(aid, maxon.Id) else maxon.Id(aid)) break return results def main() -> None : """Runs the example. """ # Make sure the asset databases have been loaded and get the user repository, i.e., the # repository where more or less all content can be found. if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading(): raise RuntimeError("Could not load asset databases.") repo: maxon.AssetRepositoryRef = maxon.AssetInterface.GetUserPrefsRepository() if not repo: raise RuntimeError("Unable to retrieve user repository.") # The final #results list where we put all the asset descriptions of image assets which are # parented to category assets with any of the IDs in #categoryIds. results: list[tuple[str, maxon.AssetDescription]] = [] # The root category we are interested in, this is the id for the "Textures/HDR" category. rootCategoryId: maxon.Id = maxon.Id("category@b9c32d04a12d449ca1c758ddb3c695b0") # Expand #rootCategoryId into a list of all its attached child categories. categoryIds: list[maxon.Id] = ExpandAssetCategoryId(repo, rootCategoryId) # The language Cinema 4D is running in, use GetDefaultLanguage() to evaluate things in engUS. currentLanguage: maxon.LanguageRef = maxon.Resource.GetCurrentLanguage() def onSearchHit(asset: maxon.AssetDescription) -> bool: """Called for each asset by the FindAssets() call below. Assets which match the search criteria are written to #results. """ # Get the metadata of the asset and assert that its subtype is MediaImage, step over an asset # when these operations fail. metadata: maxon.AssetMetaData = asset.GetMetaData() if metadata is None: return True sid: maxon.InternedId = maxon.InternedId(metadata.Get(maxon.ASSETMETADATA.SubType, maxon.Id())) if sid != maxon.ASSETMETADATA.SubType_ENUM_MediaImage: return True # Append the name of the asset and the asset itself to the results when #asset is parented # to a category asset with an ID which is contained ins #categoryIds. if maxon.CategoryAssetInterface.GetParentCategory(asset) in categoryIds: results.append((asset.GetMetaString(maxon.OBJECT.BASE.NAME, currentLanguage, ""), asset)) return True # Search #repo for all file type assets (this includes MediaImage assets) with any id and pass # the data through onSearchHit. repo.FindAssets( assetType=maxon.AssetTypes.File(), aid=maxon.Id(), version=maxon.Id(), findMode=maxon.ASSET_FIND_MODE.LATEST, receiver=onSearchHit) # Print the expanded category IDs and the first five asset matches associated with them. print (f"{categoryIds = }") for name, asset in results[:5]: print (f"{name = }, {asset.GetId() = }") if __name__ == "__main__": main()
  • Paste JSON Values on the Node Network?

    r25 python
    7
    0 Votes
    7 Posts
    1k Views
    B
    @iplai ah yep. I'll probably use this one since it does not require third party library. haha. Thanks for the illustration!
  • Get the Name of the Node?

    r25 python
    7
    0 Votes
    7 Posts
    1k Views
    M
    You have to be careful since the value returned by effectivename will change according of the Cinema 4D language. The best way is really to work with IDs. Cheers, Maxime
  • How to Use ListAllNodes?

    r25 python
    5
    0 Votes
    5 Posts
    848 Views
    ferdinandF
    Hello @bentraje @bentraje said in How to Use ListAllNodes?: doc: c4d.documents.BaseDocument # The active document. I'm not too familiar with the Python 3 syntax but this line returns an empty graph down the line. Tha is a bit odd, especially since I tested and ran the code with R25. This line or code such as below # Without type hinting. def foo(a): return f"{a}" # With type hinting. def foo(a: typing.Any) -> str: return f"{a}" makes use of type hinting. It tries to rectify ambiguities that come with the fact that Python is dynamically typed. For now, type hinting has no real impact on code run on CPython (i.e., the "standard" Python), unless you use special libraries to run your CPython code or use interpreters other than CPython which support static or at least asserted typing out of the box. All the line doc: c4d.documents.BaseDocument # The active document. does for now is: Make code more readable by telling humans what the module attribute doc is and that it exists in the first place. Enable auto-complete engines as provided by, for example, VSCode to give you smart suggestions. Enable linters or runtime libraries to run type assertions on your code. Adding or removing this line should have zero impact on the execution, unless you added there an equals sign and overwrote the value of doc. Cheers, Ferdinand
  • How to change bitmap in layered shader?

    python r19
    3
    0 Votes
    3 Posts
    1k Views
    V
    Perfect! Thank you so much!
  • Python tag wrong angle output in console

    python
    3
    2
    0 Votes
    3 Posts
    376 Views
    C
    Hi Ferdinand, Thanks for your in-depth answer! Cheers, Casimir Smets
  • How to render a animation preview ?

    sdk s26 python
    7
    0 Votes
    7 Posts
    1k Views
    M
    Hi @Dunhou you can't control the Make Preview plugin, you have to rewrite the function yourself with all the tips previously shared in this topic. Cheers, Maxime.
  • Append string the node path in retrieving the port?

    python r25
    3
    0 Votes
    3 Posts
    338 Views
    B
    @ferdinand Thanks for the clarification and offering some alternatives. I guess it has something do with how it was designed. There is a FindChild equivalent in other DCC API too like in maya there is a GetAttr or something. But again, if you know the actual parameter/attribute path like texturenode.tex0.colorspace texturenode.uv.uv_channel texturenode.remape.scale.x There's no need. It's straightforward. You use that instead. Anyhow, will close this thread now.
  • API for Project Asset Inspector?

    r25 python
    3
    0 Votes
    3 Posts
    740 Views
    B
    @ferdinand Thanks for the response. RE: we never expose managers themselves Gotcha. Thanks for the clarification RE: Code Works as expected. Closing this thread now.
  • Change the ColorSpace of Redshift Texture Node?

    r25 python
    6
    1
    1 Votes
    6 Posts
    1k Views
    B
    @Dunhou @Manuel Thanks for the response. I ended up going for the ctrl+C on the node editor Pretty straightforward and works as expected. Functions like how you copy/paste nodes on Fusion and Nuke.
  • Creation of UVW tag for a plane

    Moved
    2
    1
    0 Votes
    2 Posts
    475 Views
    ManuelM
    hi, you can use CallUVCommand. The forum also has different thread already talking about it. This one for example, explain how to use command to pack your UVs. It shows how to automatically unwarp your model and answer what you are looking for. This is done using SendModelingCommand with some parameters, those parameters can be found here in the c++ documentation. Of course, you can also create the uvw tag yourself and define the uvw coordinates as you wish. You have this thread for example that shows how to do a planar projection. Cheers, Manuel
  • Python scripting tag editing object position and points

    python
    3
    0 Votes
    3 Posts
    381 Views
    C
    Hi Ferdinand, Thanks a lot for your in-depth answer! I was assuming it was possible, but now I know for sure! Cheers, Casimir Smets
  • Selection Order Flag for GetActiveMaterials?

    r25 python
    3
    0 Votes
    3 Posts
    318 Views
    B
    @Manuel Gotcha. Thanks for the confirmation.