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 assets to a userdatabase in the assetbrower with Python

    Bugs
    python
    3
    9
    997
    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.
    • W
      wen
      last edited by

      I'm trying to add my materials to the asset browser through a python script. I'm basing my script on the code examples from: https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/tree/master/scripts/05_modules/assets
      The thing I can't seem to figure out is how to add an asset to a user database instead of one of the standard databases.
      In the examples a repository is given as an argument to the storeAssetStruct function who's result is passed to the CreateMaterialAsset function that stores the asset to the assetbrowser.

      repository = maxon.AssetInterface.GetUserPrefsRepository()
      storeAssetStruct = maxon.StoreAssetStruct(assetCategoryId, repository, repository)
      assetDescription = maxon.AssetCreationInterface.CreateMaterialAsset(doc, mat, storeAssetStruct, assetId, assetName, assetVersion, assetMetadata, True)
      

      From what I understand the UserPrefsRepository tells the function to use the standard database Preferences. This leads me to think I would need to find the repository for the userdatabases. I can find the database object but have no clue how to get to the repository from there. Can you point me in the right direction?

      Thanks, Bart

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

        Hey @wen,

        Thank you for reaching out to us. Have you checked asset_databases_r26.py? That should cover all your needs for creating and mounting user asset databases. Specifically, the CreateRepositories and MountAssetDatabase examples are probably what you are looking for.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        W 1 Reply Last reply Reply Quote 0
        • W
          wen @ferdinand
          last edited by

          Hi @ferdinand

          Going over it a bit more indepth I see this could work for what I want. It does leave me with a question though:

          # Iterate over all currently mounted databases and create an asset repository for each of them.
          # Doing this is usually not necessary as user asset databases are automatically part of the
          # the user preferences repository which is easier to retrieve. Creating a repository for a
          # specific user asset database can be useful to speed up asset searches.
          

          I was under the assumption userdatabases are by default already part of some other repository than the standard ones. Here it's stated they automaticlally become part of the user preferences repository. Does that mean I can somehow specify which database to use if there are multiple in the user preferences repository?

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

            Hey @wen,

            Well, the elephant in room is probably that we misnamed the two central entities in the Asset API, which often leads to confusion.

            When the Asset API talks about databases, it means physical storage locations, i.e., what is usually called a repository. And when the Asset API talks about repositories, it means the logical interface(s) to such physical storage locations, i.e., what is usually referred to as a database or DBMS. In the C++ documentation I then defused the situation a bit by explaining it, but it is still misleading.

            The comment you cite uses the terminology we chose then (but is effectively inverted). When you iterate over the physical storage locations of assets ('databases'), you can construct logical interfaces ('repositories') for these storage locations individually. But for search operations this is usually not necessary because our logical interfaces ('repositories') work like Russian nesting dolls, where search interfaces can be stacked into each other to handle multiple physical locations under one interface (the bases of a repository). So, when you just want to search for an asset stored in some user database, you can use the user preferences repository, as this exposes all currently active repositories of a Cinema 4D instance.

            When you want to write to a specific physical storage location, you will have to construct a logical interface for that location. Because the user preferences repository will write into the database which is stored in the prefs folder of the user.

            Cheers,
            Ferdinand

            MAXON SDK Specialist
            developers.maxon.net

            W 1 Reply Last reply Reply Quote 1
            • W
              wen @ferdinand
              last edited by

              @ferdinand
              Trying the CreateRepositories() function from the example I'm getting an error. I did not make any changes to the code. Did something change internally perhaps?

              Traceback (most recent call last):
                File "scriptmanager", line 42, in <module>
                File "scriptmanager", line 32, in CreateRepositories
                File "C:\Program Files\Maxon Cinema 4D 2025\resource\modules\python\libs\python311\maxon\decorators.py", line 495, in Auto
                  ExecStaticMethod(*args)
              TypeError: unable to convert builtins.NativePyData to @net.maxon.interface.class-cR
              

              This line seems to be the problem:

              repository = maxon.AssetInterface.CreateRepositoryFromUrl(rid, bases, database._dbUrl, True, False, False)
              
              W 1 Reply Last reply Reply Quote 0
              • W
                wen @wen
                last edited by

                @ferdinand Could you or someone else please confirm this code works on your end? It's from the examples. I tried it in 2023 and 2025 and can't really think of anything to get it running. I had a look at the decorators.py that's trowing the error but that stuff's a bit over my head.

                Thanks, Bart

                import maxon
                
                def CreateRepositories():
                    """Creates repositories for all user databases.
                
                    Doing this is usually not necessary for performing light- to medium-sized asset operations, and
                    the user preferences repository can then be used instead. Only when there is a substantial
                    amount of assets that must be processed, a repository should be constructed to limit the
                    search space for search operations. The method CreateRepositoryFromUrl() used in this example
                    can also be used to create a repository and its underlying database from scratch when the
                    provided URL points to location where no database has been established yet.
                    """
                    # Wait for all asset databases to be loaded, abort when this is not possible.
                    if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
                        return RuntimeError("Could not load asset databases.")
                
                    # Get the default language of Cinema 4D (en-US) for retrieving the repository names.
                    defaultLanguage = maxon.Resource.GetDefaultLanguage()
                
                    # Iterate over all currently mounted databases and create an asset repository for each of them.
                    # Doing this is usually not necessary as user asset databases are automatically part of the
                    # the user preferences repository which is easier to retrieve. Creating a repository for a
                    # specific user asset database can be useful to speed up asset searches.
                    for database in maxon.AssetDataBasesInterface.GetDatabases():
                
                        # Create a unique identifier for the repository.
                        rid = maxon.AssetInterface.MakeUuid(str(database._dbUrl), True)
                
                        # Repositories can be composed out of other repositories which are called bases. In this
                        # case no bases are used to construct the repository. But with bases a repository for all
                        # user databases could be constructed for example.
                        bases = maxon.BaseArray(maxon.AssetRepositoryRef)
                
                        # Create a writable and persistent repository for the database URL. If #_dbUrl would point
                        # to a location where no database has been yet stored, the necessary data would be created.
                        repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                            rid, bases, database._dbUrl, True, False, False)
                        if not repository:
                            raise RuntimeError("Repository construction failed.")
                
                        # Access some properties of the newly created repository.
                        repoId = repository.GetId()
                        isWriteable = repository.IsWritable()
                        name = repository.GetRepositoryName(defaultLanguage)
                
                        print(f"{repository} ({name}): id - {repoId}, writeable: {isWriteable}")
                
                CreateRepositories()
                
                1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand
                  last edited by ferdinand

                  Hey, @wen I saw your message, but we do not always have the time to answer directly. Maxime will have a look on Monday. For me this runs fine, but Maxime said we internally had a similar report.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  W 1 Reply Last reply Reply Quote 0
                  • W
                    wen @ferdinand
                    last edited by

                    @ferdinand
                    Thanks for the clarification. I saw you replying to other post and thought: "Perhaps he didn't see or there is no easy answer"
                    It's nice to know someone will have a further look and come back to it later on. On some support forums that's not always the case.
                    I had my collegues try the function aswell and it doesn't work for them either. Let's hope Maxime know's what's happening.

                    1 Reply Last reply Reply Quote 0
                    • M m_adam moved this topic from Cinema 4D SDK on
                    • M
                      m_adam
                      last edited by m_adam

                      Hi @wen I've moved your topic to the bug section since it's indeed a bug, I will ping you on this topic once the fix is available, it should come in one of the next update.
                      The issue is that the internal cache is not properly updated and therefor this is failing.

                      With that's said there is a ugly workaround which consist of calling it twice so the cache is properly updated.
                      Find bellow a version that is going to work in all versions

                      import c4d
                      import maxon
                      import os
                      
                      
                      def CreateRepFromUrl(url: maxon.Url) -> maxon.UpdatableAssetRepositoryRef:
                          """Create a new repository from a given database URL.
                          
                          If there is no valid database at the given URL, it creates a database at the URL.
                          It always create a new repository and the associated database asset, even if there
                          are existing repositories for that database.
                          """
                          # Make type checks
                          if not isinstance(url, maxon.Url):
                              raise TypeError("First argument is not a maxon.Url")
                      
                          # Create a unique identifier for the repository.
                          rid = maxon.AssetInterface.MakeUuid(str(url), True)
                      
                          # Repositories can be composed out of other repositories which are called bases. In this
                          # case no bases are used to construct the repository. But with bases a repository for all
                          # user databases could be constructed for example.
                          bases = maxon.BaseArray(maxon.AssetRepositoryRef)
                      
                          # Create a writable and persistent repository for the database URL. If #_dbUrl would point
                          # to a location where no database has been yet stored, the necessary data would be created.
                          if c4d.GetC4DVersion() < 2025200:
                              try:
                                  repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                                      rid, maxon.AssetRepositoryTypes.AssetDatabase(), bases, url, True, False, False, None)    
                              except Exception as e:
                                  repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                                      rid, maxon.AssetRepositoryTypes.AssetDatabase(), bases, url, True, False, False, None)    
                          else:
                              try:
                                  repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                                      rid, maxon.AssetRepositoryTypes.AssetDatabase(), bases, url, True, False, False)    
                              except Exception as e:
                                  repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                                      rid, maxon.AssetRepositoryTypes.AssetDatabase(), bases, url, True, False, False)    
                      
                          if not repository:
                              raise RuntimeError("Repository construction failed.")
                      
                          return repository
                      
                      if __name__ == '__main__':
                          if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
                              raise RuntimeError("Could not load asset databases.")
                          dbPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "testdb")
                          print(CreateRepFromUrl(maxon.Url(dbPath)))
                      

                      Cheers,
                      Maxime.

                      MAXON SDK Specialist

                      Development Blog, MAXON Registered Developer

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