Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Adding an Object to a New Cinema 4D Asset Database

    Cinema 4D SDK
    python macos 2025
    3
    5
    632
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • d_keithD
      d_keith
      last edited by d_keith

      Hi,

      I'm attempting to write a script that will allow me to bulk-import the contents of a directcory full of .c4d files as Object Assets in a new Cinema 4D Asset Databse.

      I've found what feels like a perfect starting point by @ferdinand:
      https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/blob/master/scripts/05_modules/assets/asset_databases_r26.py

      In the documentation for MountDatabases(), he mentions:

      When the selected path does not contain an asset database, the necessary metadata will be created in that location by Cinema 4D.

      However, when I attempt to do something similar in a script, the folder mounts, but no metadata files are created and C4D doesn't react when I attempt to disable/delete the "database stub".
      46ca82ad-cc20-4793-a4f5-b1f23e909280-image.png
      e5cc6f01-1e88-49d8-b0b8-ac3326704e21-image.png

      Here's my current source code - if it looks practically identical to Ferdinand's that's because I re-wrote a lot of his methods by hand (hoping to better understand the API).

      """Name-en-US: Create Test Database
      Description-en-US: Creates a new C4D Asset Database named `_my-database.db` on your desktop."""
      
      import c4d
      import os
      import maxon
      
      def MountAssetDatabase(path):
          # Wait for all existing dbs to load
          if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
              return RuntimeError("Could not load asset databases.")
      
          # Build a maxon url from the path
          url = maxon.Url(path)
          databaseCollection = maxon.AssetDataBasesInterface.GetDatabases()
      
          # Check if DB is already mounted
          for database in databaseCollection:
              print(database)
      
              if database._dbUrl == url:
                  database._active = True
                  maxon.AssetDataBasesInterface.SetDatabases(databaseCollection)
                  return database
      
          database = maxon.AssetDatabaseStruct(url)
          databaseCollection.append(database)
          maxon.AssetDataBasesInterface.SetDatabases(databaseCollection)
          print(f"Created new DB for '{url}'")
      
          return database
      
      def main():  
          # Get the user's desktop path
          desktop_path = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_DESKTOP)
          
          # Define the database file path
          name = "_my-database.db"
          path = os.path.join(desktop_path, name)
          
          # Create the database if it doesn't exist
          if not os.path.exists(path):
              os.makedirs(path, exist_ok=True)
      
          database = MountAssetDatabase(path)
          c4d.storage.ShowInFinder(path, open=True)
      
      # Execute the script
      if __name__ == '__main__':
          main()
      

      Am I misunderstanding what should happen - or is it not working as expected?

      1 Reply Last reply Reply Quote 0
      • d_keithD
        d_keith
        last edited by

        Update: I've found found a workable solution, but still have some questions (listed at bottom)

        @ferdinand - I tried to edit the original post to avoid a "diary" post, but ran into the following error:

        You are only allowed to edit posts for 3600 second(s) after posting

        """Name-en-US: Import Directory as Object Assets Database
        Description-en-US: Creates a new C4D Asset Database named `_my-database.db` on your desktop, and loads the first object of each .c4d project in `_assets`
        
        References:
        https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/blob/master/scripts/05_modules/assets/asset_databases_r26.py
        https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/blob/master/scripts/05_modules/assets/asset_types_r26.py
        
        """
        
        ## Imports
        
        import c4d
        import os
        import maxon
        
        ## User Inputs
        
        # TODO: Add input paths, otherwise default paths will be used
        
        INPUT_PROJECTS_DIR = ""
        OUTPUT_ASSETS_DB = ""
        
        ## Helpers
        
        def CreateRepoFromPath(path) -> maxon.UpdatableAssetRepositoryRef:
            # Wait for all existing dbs to load
            # Not sure if this is needed or superstitious
            if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
                return RuntimeError("Could not load asset databases.")
        
            url = maxon.Url(path)
            if url.IoDetect() == maxon.IODETECT.ERRORSTATE:
                raise RuntimeError(f"Directory {url} is invalid")
        
            repo_id = maxon.AssetInterface.MakeUuid(str(url), True)
            bases = maxon.BaseArray(maxon.AssetRepositoryRef)
            try:
                repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                    repo_id,
                    maxon.AssetRepositoryTypes.AssetDatabase(),
                    bases,
                    url,
                    True,
                    False,
                    False,
                )
            except Exception as e:
                # If at first you don't succeed, try... try... again.
                repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                    repo_id,
                    maxon.AssetRepositoryTypes.AssetDatabase(),
                    bases,
                    url,
                    True,
                    False,
                    False,
                )
        
            if not repository:
                raise RuntimeError("Could not create Repository.")
        
            return repository
        
        def MountAssetDatabase(path):
            # Wait for all existing dbs to load
            if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
                return RuntimeError("Could not load asset databases.")
        
            # Build a maxon url from the path
            url = maxon.Url(path)
            databaseCollection = maxon.AssetDataBasesInterface.GetDatabases()
        
            # Check if DB is already mounted
            for database in databaseCollection:
                print(database)
        
                if database._dbUrl == url:
                    database._active = True
                    maxon.AssetDataBasesInterface.SetDatabases(databaseCollection)
                    return database
        
            database = maxon.AssetDatabaseStruct(url)
            databaseCollection.append(database)
            maxon.AssetDataBasesInterface.SetDatabases(databaseCollection)
        
            return database
        
        def AddObjectToRepository(
            repo: maxon.UpdatableAssetRepositoryRef,
            doc: c4d.documents.BaseDocument,
            obj: c4d.BaseObject,
        ):
            if repo is None:
                raise ValueError("Invalid repo")
        
            if obj is None:
                raise ValueError("Input obj does not exist")
        
            asset_id = maxon.AssetInterface.MakeUuid(prefix="object", compact=False)
            asset_name = obj.GetName()
            asset_version = (
                "0.1.0"  # Using Semantic Versioning, as we rarely get it right the first time.
            )
            asset_metadata = maxon.AssetMetaData()
            asset_category_id = maxon.Id("net.maxon.assetcategory.uncategorized")
        
            store_asset_struct = maxon.StoreAssetStruct(asset_category_id, repo, repo)
            asset = maxon.AssetCreationInterface.CreateObjectAsset(
                obj,
                doc,
                store_asset_struct,
                asset_id,
                asset_name,
                asset_version,
                asset_metadata,
                True,
            )
        
            return asset
        
        
        def OpenAssetBrowser():
            # The command id for the Asset Browser.
            CID_ASSET_BROWSER = 1054225
        
            # Open the Asset Browser when it is not already open.
            if not c4d.IsCommandChecked(CID_ASSET_BROWSER):
                c4d.CallCommand(CID_ASSET_BROWSER)
        
        
        ## Main
        
        
        def main():
            # Get the user's desktop path
            desktop_path = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_DESKTOP)
        
            # Get the Input File Path
            assets_dir = INPUT_PROJECTS_DIR
            if not assets_dir:
                assets_dir = os.path.join(desktop_path, "_assets")
        
            # Define the output database path
            database_name = "_my-database.db"
            database_path = OUTPUT_ASSETS_DB
            if not database_path:
                database_path = os.path.abspath(os.path.join(desktop_path, database_name))
        
            # Create the database if it doesn't exist
            if not os.path.exists(database_path):
                os.makedirs(database_path, exist_ok=True)
        
            repository = CreateRepoFromPath(database_path)
        
            doc = c4d.documents.GetActiveDocument()
            obj = doc.GetActiveObject()
        
            # Iterate through all *.c4d files in the assets directory
            assets = []
            for file_name in os.listdir(assets_dir):
                if file_name.endswith(".c4d"):
                    file_path = os.path.join(assets_dir, file_name)
        
                    # Load the C4D file silently
                    loaded_doc = c4d.documents.LoadDocument(
                        file_path, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS, None
                    )
                    if loaded_doc is None:
                        print(f"Failed to load {file_path}")
                        continue
        
                    # Get the first object in the loaded document
                    obj = loaded_doc.GetFirstObject()
                    if obj is None:
                        print(f"No objects found in {file_path}")
                        continue
        
                    # Add the object to the repository
                    asset = AddObjectToRepository(repository, loaded_doc, obj)
                    if asset is None:
                        raise RuntimeError(f"Unable to ingest {file_name}")
        
                    assets.append(asset)
        
                    # Unload/close the loaded document
                    c4d.documents.KillDocument(loaded_doc)
        
            database = MountAssetDatabase(database_path)
        
            maxon.AssetManagerInterface.RevealAsset(assets)
            c4d.EventAdd()
        
            c4d.storage.ShowInFinder(database_path, open=True)
        
        
        
        # Execute the script
        if __name__ == "__main__":
            main()
        
        

        Questions

        1. Should I be able to mount a directory and have it auto-create a DB?
        2. Any idea why I need to re-try creating the Repo for it to work?
        3. If I run this script multiple times, I end up with multiple DBs in the same directory - any way to get CreateRepoFromUrl() to detect that there's already a repo so it doesn't need to create one, and can instead just load it?
        4. Show Assets doesn't seem to be doing what I want. I typically have to manually close/reopen the Assets Browser a couple of times to see an update. Is there an event I need to add to immediately show the assets?

        Thanks!

        ferdinandF i_mazlovI 2 Replies Last reply Reply Quote 0
        • ferdinandF
          ferdinand @d_keith
          last edited by ferdinand

          Hey @d_keith,

          I am briefly on vacation, so it will probably take a week before I can have a look. But you are in good hands with the rest of the SDK team 🙂 But, yes, you should be able to create a repo (i.e., asset database) with CreateRepositoryFromUrl and when the passed URL already contains a repo, it should not create a new one. That was at least its S26 behavior, it could be that Tilo has changed that since then. If I remember correctly, Daniel reported something similar about that function not respecting existing repos, or at least that it created a database asset each time for being called (not the same as an entire new repo and probably what you mean).

          The TLDR aside from the concrete support case is: Please create tickets for bugs, when the documentation says one thing, and the function does another thing, this is at least worthy of being a bug candidate. When this is super urgent for you and Ilia or Maxime do not have an answer right away, you could also ask Tilo or talk with Daniel what he did.

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by

            FYI: I also turned off the edit limit for new users of 3600 seconds, I guess the system views you as a new user with 12 postings.

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 0
            • i_mazlovI
              i_mazlov @d_keith
              last edited by i_mazlov

              Hi @d_keith,

              I would kindly ask you to check our Support Procedures, namely the "How To Ask Questions" paragraph:

              Singular Question: The initial posting of a support topic must contain a singular question. Do not ask ten things at once, that makes it extremely hard to answer topics. Break up your questions into multiple topics.

              Here you effectively have 4 different questions about Asset Browser, and these are candidates for 4 different threads on the forum. In your further postings please try to follow the aforementioned rules.

              Regarding your questions:

              1. Should I be able to mount a directory and have it auto-create a DB?

              Mounting database is effectively executing the AssetDataBasesInterface.SetDatabases. It has nothing to do with creating database neither semantically, nor is this mentioned in the docu. If you need to create repository, please use maxon.AssetInterface.CreateRepositoryFromUrl(), it will scan the directory for being already a database and create proper dir structure if it's not.

              1. Any idea why I need to re-try creating the Repo for it to work?

              If you face any errors in the script, please always attach at least the error message! In this case I assume you receive the following error, when executing the maxon.AssetRepositoryTypes.AssetDatabase() for the first time after Cinema 4D started. Looks like a bug to me, I've created a bug report for that (ITEM#585831).

              The error message:

              Traceback (most recent call last):
                File "console", line 1, in <module>
                File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\interface.py", line 5049, in __call__
                  self._cachedObj.R = _maxon_mapping.GetAssociatedDataType(dt)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
              Exception: unable to find datatype
              

              As a workaround you can just execute the following line first in your main():

              maxon.AssetRepositoryTypes.AssetDatabase()
              
              1. ... about multiple DBs ...

              You're giving your databases unique IDs with the line repo_id = maxon.AssetInterface.MakeUuid(str(url), True). If you need them to be the same, just pick one instead, e.g. repo_id = maxon.Id('net.maxon.sdk.cool.things.repo')

              1. ... revealing assets doesn't work...

              I've created a bug report for that, as it looks like a bug with refreshing in the Asset Browser. As a workaround you can reload databases and reopen the AB before reveling your assets, e.g.:

              def RepenAssetBrowser():
                  CID_ASSET_BROWSER = 1054225
              
                  # Close the Asset Browser if it's alredy opened
                  if c4d.IsCommandChecked(CID_ASSET_BROWSER):
                      c4d.CallCommand(CID_ASSET_BROWSER)
                  
                  # Open again
                  c4d.CallCommand(CID_ASSET_BROWSER)
              
              def main():
              	# ...
              	# assets = []
              	# ...
              	# assets.append(asset)
              	# ...
              	
                  maxon.AssetDataBasesInterface.ReloadAssetRepositories(True)
                  RepenAssetBrowser()
                  maxon.AssetManagerInterface.RevealAsset(assets)
              

              Cheers,
              Ilia

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 1
              • First post
                Last post