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

    Plugins Search Path from Preferences

    Cinema 4D SDK
    python
    2
    3
    611
    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.
    • merkvilsonM
      merkvilson
      last edited by

      Hello.
      I'm trying to access and subsequently modify Plugins Search Path, which is located in the Preferences window.
      I have to accomplish this task via a Python script (not from pyp file).

      I have a problem at the first step when I'm trying to simply access its value and print it.

      import c4d
      
      pid, att = None, c4d.plugins.GetFirstPlugin()
      while att:
          if 'Plugins/Plugins' in str(att):
              pid = att.GetID()
              break
          att = att.GetNext()
      
      prefs = c4d.plugins.FindPlugin(pid)
      plugins = prefs[c4d.PREF_PLUGINS_PATHS]
      print(prefs[c4d.PREF_PLUGINS_PATHS])
      

      In this example, it prints an empty string even though several paths are already added.

      However, if I open the preferences window, it prints the correct values instead of an empty string. Is it possible to bypass opening the prefs window and make the script work correctly?

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

        Hello @merkvilson,

        thank you for reaching out to us. That is unfortunately not possible because the preference node for the Plugins section in the preferences is designed in a manner which prevents that. It reads the necessary data only when its GetDDescription method is being called. I.e., the plugin paths parameter is only populated once you have opened the preferences dialog, causing GetDDescription of that node being called. I personally think this is bad design, but our developers seem to disagree, so it probably will stay as is.

        What you can do is read the values from the plugins.json file at the root of the preference directory of the running Cinema 4D instance. The JSON file is however serialized with our DescribeIO routines, so it will look something like this for a singular path:

        {
          "identification": "plugins",
          "content": {
            "referenceDataType": "net.maxon.interface.datadictionary-C",
            "_impl": {
              "_mode": 2,
              "_data": [
                {
                  "dataType": "net.maxon.datatype.id",
                  "content": "searchPaths"
                },
                {
                  "dataType": "(net.maxon.interface.url-C,bool)",
                  "isArray": true,
                  "content": [
                    {
                      "_0": {
                        "referenceIndex": 0,
                        "referenceDataType": "net.maxon.interface.url-C",
                        "_scheme": "file",
                        "_path": "/Path/To/Plugin/Directory/",
                        "_authority": {},
                        "_data": {}
                      },
                      "_1": true
                    }
                  ]
                }
              ]
            }
          }
        }
        

        When we decide to change something about the object which is being serialized into this file, currently a DataDictionary, also this file will change. I know that this is not a very satisfying solution, but unfortunately the best we can currently offer.

        For your understanding: When DesribeIO is serializing key-value pair types, it puts them into a list in the form: key, value, key, value, key, value, .... The DataDictionary which is serialized above stores its data under the _data key. So _data must here be read in the manner that this dictionary has a key searchPaths which stores the following value, which is an array of Url, bool tuples, expressing a plugin path and its activation state, which is then decomposed into its parts.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        merkvilsonM 1 Reply Last reply Reply Quote 0
        • merkvilsonM
          merkvilson @ferdinand
          last edited by merkvilson

          Thanks @ferdinand

          I wrote this little script for those who want to add one plugin path via the C4D script. I will update it later.
          It will NOT overwrite existing paths. Restart is required for instant result.

          import c4d
          import os
          import json
          
          
          def add_plugin_path(path, restart = False):
          
              if os.path.exists(path): new_path = path.replace("\\", "/")
              else:
                  print("Path does not exists")
                  return
          
              prefs_folder      = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_PREFS)
              prefs_path        = os.path.dirname(prefs_folder)
              plugins_json_path = os.path.join(prefs_path, 'plugins.json')
          
          
              if os.path.exists(plugins_json_path):
                  with open(plugins_json_path,'r',encoding="utf-8-sig") as plugins: plugins_json_raw = plugins.read()
                  plugins_dict = json.loads(plugins_json_raw)
                  content_dict = plugins_dict["content"]["_impl"]["_data"][1]["content"]
          
                  # Check if the new path is already in Plugins Path
                  for content_path in content_dict:
                      if os.path.normpath(content_path["_0"]["_path"]) == os.path.normpath(new_path):
                          print(f"'{new_path}' is already in Plugins Path.")
                          return
          
              else:
                  plugins_dict = {
                      'identification': 'plugins',
                      'content': {
                          'referenceDataType': 'net.maxon.interface.datadictionary-C',
                              '_impl': {
                                  '_mode': 2,
                                  '_data': [
                                      {
                                          'dataType': 'net.maxon.datatype.id',
                                          'content': 'searchPaths'
                                      },
                                      {
                                          'dataType': '(net.maxon.interface.url-C,bool)',
                                          'isArray': True,
                                          'content': []}]}}}
          
          
          
              # Create new path content
              new_content = {
                  "_0": {
                      "referenceIndex": len(plugins_dict["content"]["_impl"]["_data"][1]["content"]),
                      "referenceDataType": "net.maxon.interface.url-C",
                      "_scheme": "file",
                      "_path": new_path,
                      "_authority": {},
                      "_data": {}
                  },
                  "_1": True
              }
          
              # Append the new path to the list of paths
              plugins_dict["content"]["_impl"]["_data"][1]["content"].append(new_content)
          
              # Convert the dictionary back to a JSON string
              updated_plugins_dict = json.dumps(plugins_dict, indent=4)
          
              # Write the updated dictionary back to a JSON file
              with open(plugins_json_path, 'w') as plugins_json: plugins_json.write(updated_plugins_dict)
          
              if restart: c4d.RestartMe()
          
          custom_path = r"/Path/To/Plugin/Directory/"
          
          add_plugin_path(path = custom_path, restart = False)
          
          1 Reply Last reply Reply Quote 2
          • First post
            Last post