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

    Python: Detect Plugins

    Cinema 4D SDK
    2024 python windows
    3
    12
    2.2k
    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.
    • J
      JohnThomas
      last edited by

      Thanks for the response.

      Your code seems to work for Python plugins but is there a way to detect if something is a plugin for an xdl64 or xlib. I know that I could just check if the plugin ends with either of those but a Cube also counts as a plugin with either an xdl64 or xlib. Is there a way to tell if it is a Cinema plugin in this way or a user added one?

      With the Maxon One question, is there a way to tell if a scene is Maxon One dependent without being able to detect a Maxon One object specifically?

      John Thomas

      1 Reply Last reply Reply Quote 0
      • ThomasBT
        ThomasB @m_adam
        last edited by

        @m_adam
        Sorry, little question, what does the python extenstion "pype" mean?

        Thanks,
        T.S.B

        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by

          Hi John Thomas, sorry I missed your reply, you can do the same by checking if the path is not part of the "corelibs" folder or the Redshift one.
          Find bellow an example bellow, I just did a string comparison, for a safer approach you will need to compare with the absolute path.

          import c4d
          
          
          def HierarchyIterator(bl2d):
              while bl2d:
                  yield bl2d
                  for opChild in HierarchyIterator(bl2d.GetDown()):
                      yield opChild
                  bl2d = bl2d.GetNext()
          
          def IsPythonPlugin(bl2d):
              basePlugin = c4d.plugins.FindPlugin(bl2d.GetType())
              pluginFile = basePlugin.GetFilename()
              return pluginFile.endswith("pyp") or pluginFile.endswith("pypv") or pluginFile.endswith("pype")
          
          def isCppPlugins(bl2d):
              if IsPythonPlugin(bl2d):
                  return False
              
              basePlugin = c4d.plugins.FindPlugin(bl2d.GetType())
              pluginFile = basePlugin.GetFilename()
              
              return not ("corelibs" in pluginFile or "Redshift" in pluginFile)
          
          def main() -> None:
              for obj in HierarchyIterator(doc.GetFirstObject()):
                  print(IsPythonPlugin(obj), isCppPlugins(obj))
          
          if __name__ == '__main__':
              main()
          

          @ThomasB pype is the old encryption file format for python plugin file (you can't create them since R16 but you can still load them).

          Cheers,
          Maxime.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • J
            JohnThomas
            last edited by

            Thanks for the response, the code seems to work as hoped for detecting a plugin.

            Have you had a chance to look into detecting a Maxon One capsule?

            John Thomas

            1 Reply Last reply Reply Quote 0
            • J
              JohnThomas
              last edited by

              Any luck with detecting Maxon One?

              John Thomas

              1 Reply Last reply Reply Quote 0
              • J
                JohnThomas
                last edited by

                Any luck with detecting Maxon One?

                John Thomas

                1 Reply Last reply Reply Quote 0
                • M
                  m_adam
                  last edited by m_adam

                  Hi @JohnThomas first of all you will only be able to add Maxon One assets in the Cinema 4D instance that has Maxon One. If you do not have Maxon One you will still see Maxon One assets in the asset browser, and you can find their asset description and get their meta data but you cant load the asset.
                  With that's said the license information about an asset is stored in it's asset description meta data. You can get the license information about any asset like so:

                  import c4d
                  import maxon
                  
                  class ASSETLICENSETYPE:
                      ALLBITS = (1 << 30) | ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10) | (1 << 12)) | ((1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 11) | (1 << 13))
                      ENABLE_IN_ALL = (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10) | (1 << 12)
                      ENABLE_IN_CINEWARE = 1 << 12
                      ENABLE_IN_EDUCATION = 1 << 10
                      ENABLE_IN_LITE = 1 << 6
                      ENABLE_IN_PERPETUAL = 1 << 2
                      ENABLE_IN_STUDENT = 1 << 8
                      ENABLE_IN_SUBSCRIPTION = 1 << 0
                      ENABLE_IN_TRIAL = 1 << 4
                      NONE = 0
                      ONLY_IN_MAXONONE = 1 << 30
                      SHOW_IN_ALL = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 11) | (1 << 13)
                      SHOW_IN_CINEWARE = 1 << 13
                      SHOW_IN_EDUCATION = 1 << 11
                      SHOW_IN_LITE = 1 << 7
                      SHOW_IN_PERPETUAL = 1 << 3
                      SHOW_IN_STUDENT = 1 << 9
                      SHOW_IN_SUBSCRIPTION = 1 << 1
                      SHOW_IN_TRIAL = 1 << 5
                  
                  def GetAssetDescription(assetId: str) -> maxon.AssetDescription:
                      repository = maxon.AssetInterface.GetUserPrefsRepository()
                      if not repository:
                          raise RuntimeError("Could not access the user preferences repository.")
                  
                      assetDescription = repository.FindLatestAsset(maxon.AssetTypes.File(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
                          if not assetDescription or assetDescription.IsNullValue():
                              assetDescription = repository.FindLatestAsset(maxon.AssetTypes.NodeTemplate(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
                          if not assetDescription:   
                              raise RuntimeError(f"Could not find the '{assetId}' asset.")
                  
                      return assetDescription
                  
                  
                  def TestLicenses(licenses, flag):
                      out = [False] * len(licenses)
                      for i, lic in enumerate(licenses):
                          out[i] = bool(lic & flag)
                          
                      return out
                  
                  
                  def main() -> None:
                      everyoneAssetId = "file_faaca247ca4107d0"
                      everyoneAssetDescription = GetAssetDescription(everyoneAssetId)
                      everyoneLicense = everyoneAssetDescription.GetMetaData().Get(maxon.ASSETMETADATA.ValidLicenseType)
                      
                      subscriptionAssetId = "file_e0f13aae45bf949e"
                      subAssetDescription = GetAssetDescription(subscriptionAssetId)
                      subLicense = subAssetDescription.GetMetaData().Get(maxon.ASSETMETADATA.ValidLicenseType)
                          
                      mxOnlyAssetId = "object_6ae75db1dd872ee61a81cc637cf7aa24"
                      mxOnlyAssetDescription = GetAssetDescription(mxOnlyAssetId)
                      mxOnlyLicense = mxOnlyAssetDescription.GetMetaData().Get(maxon.ASSETMETADATA.ValidLicenseType)
                      
                      # Finally test all licenses
                      licenses = [everyoneLicense, subLicense, mxOnlyLicense]
                      inAll = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_ALL)
                      sub = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_SUBSCRIPTION)
                      perpetual = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_PERPETUAL)
                      trial = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_TRIAL)
                      lite = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_LITE)
                      student = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_STUDENT)
                      edu = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_EDUCATION)
                      cineware = TestLicenses(licenses, ASSETLICENSETYPE.ENABLE_IN_CINEWARE)
                      mxOne = TestLicenses(licenses, ASSETLICENSETYPE.ONLY_IN_MAXONONE)
                      
                      for i, lic in enumerate(licenses):
                          print(f"In All: {inAll[i]}, Subscription: {sub[i]}, Perpetual: {perpetual[i]}, Trial: {trial[i]}, Lite: {lite[i]}, Student: {student[i]}, Education: {edu[i]}, Cineware: {cineware[i]}, Maxon One: {mxOne[i]}")
                  
                  
                  if __name__ == '__main__':
                      main()
                  

                  With that's said the main issue is to retrieve the asset id from a given capsule in a scene. All capsules (except nodal but I will come to them latter) when they are inserted into a scene, they become part of the scene as native objects and they are not assets anymore so there is no way to tell if it come from an asset or not.
                  For nodal one it is possible but very hacky for the moment, and while it should work I do not really advice to use it on production. So find bellow a way that will work on 2024.2.0 (only look at the main function the rest are hacks to get it working).

                  import c4d
                  import maxon
                  
                  class ASSETLICENSETYPE:
                      ALLBITS = (1 << 30) | ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10) | (1 << 12)) | ((1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 11) | (1 << 13))
                      ENABLE_IN_ALL = (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10) | (1 << 12)
                      ENABLE_IN_CINEWARE = 1 << 12
                      ENABLE_IN_EDUCATION = 1 << 10
                      ENABLE_IN_LITE = 1 << 6
                      ENABLE_IN_PERPETUAL = 1 << 2
                      ENABLE_IN_STUDENT = 1 << 8
                      ENABLE_IN_SUBSCRIPTION = 1 << 0
                      ENABLE_IN_TRIAL = 1 << 4
                      NONE = 0
                      ONLY_IN_MAXONONE = 1 << 30
                      SHOW_IN_ALL = (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 11) | (1 << 13)
                      SHOW_IN_CINEWARE = 1 << 13
                      SHOW_IN_EDUCATION = 1 << 11
                      SHOW_IN_LITE = 1 << 7
                      SHOW_IN_PERPETUAL = 1 << 3
                      SHOW_IN_STUDENT = 1 << 9
                      SHOW_IN_SUBSCRIPTION = 1 << 1
                      SHOW_IN_TRIAL = 1 << 5
                  
                  @maxon.MAXON_INTERFACE(maxon.MAXON_REFERENCE_COPY_ON_WRITE, "net.maxon.node.interface.nodetemplate")
                  class NodeTemplateInterface(maxon.AssetInterface):
                      pass
                  
                  @maxon.MAXON_REFERENCE(NodeTemplateInterface)
                  class NodeTemplate(NodeTemplateInterface, maxon.Data):
                      def __new__(cls, *args):
                          return object.__new__(cls)
                  
                  @maxon.MAXON_INTERFACE(maxon.MAXON_REFERENCE_COPY_ON_WRITE, "net.maxon.node.interface.nodesystem")
                  class NodeSystemInterface(maxon.ObjectInterface):
                  
                      @maxon.MAXON_METHOD('net.maxon.node.interface.nodesystem.GetTemplate@c849c0c06c1a1ac5')
                      def GetTemplate(self):
                          pass
                  
                      @maxon.MAXON_METHOD('net.maxon.node.interface.nodesystem.GetAllBases@4292dc8effe69932')
                      def GetAllBases(self):
                          pass
                  
                  
                  @maxon.MAXON_REFERENCE(NodeSystemInterface)
                  class NodeSystem(NodeSystemInterface, maxon.Data):
                      def __new__(cls, *args):
                          return object.__new__(cls)
                  
                  def GetAssetIdFromCapsule(bl2D):
                      allNimbusRef = bl2D.GetAllNimbusRefs()
                      if not allNimbusRef:
                          raise ValueError("The given baselist 2D his is not a capsule")
                  
                      sceneNodeNimbus = allNimbusRef[0][1]
                      graph = sceneNodeNimbus.GetGraph()
                      rootNodeSystem = graph.GetBase(graph.GetRoot())
                  
                      firstNodeSystemBase = [""]
                      def GetFirstNodeSystemBase(nodeSystem):
                          firstNodeSystemBase[0] = nodeSystem.GetTemplate().GetId()
                          return False
                  
                      rootNodeSystem.GetAllBases(GetFirstNodeSystemBase)
                      if not firstNodeSystemBase[0]:
                          return rootNodeSystem.GetTemplate().GetId()
                  
                      return firstNodeSystemBase[0]
                  
                  def GetAssetDescription(assetId: str) -> maxon.AssetDescription:
                      repository = maxon.AssetInterface.GetUserPrefsRepository()
                      if not repository:
                          raise RuntimeError("Could not access the user preferences repository.")
                  
                      assetDescription = repository.FindLatestAsset(maxon.AssetTypes.File(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
                      if not assetDescription or assetDescription.IsNullValue():
                          assetDescription = repository.FindLatestAsset(maxon.AssetTypes.NodeTemplate(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
                      if not assetDescription:   
                          raise RuntimeError(f"Could not find the '{assetId}' asset.")
                  
                      return assetDescription
                  
                  def TestLicenses(lic, flag):
                      return bool(lic & flag)
                  
                  
                  def main() -> None:
                      capsuleAssetId = GetAssetIdFromCapsule(op)
                      capsuleAssetDescription = GetAssetDescription(capsuleAssetId)    
                      capsuleLicense = capsuleAssetDescription.GetMetaData().Get(maxon.ASSETMETADATA.ValidLicenseType, ASSETLICENSETYPE.NONE)
                  
                      print(f"Asset Id: {capsuleAssetId}")
                  
                      if capsuleLicense != ASSETLICENSETYPE.NONE:
                          # Test the license
                          inAll = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_ALL)
                          sub = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_SUBSCRIPTION)
                          perpetual = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_PERPETUAL)
                          trial = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_TRIAL)
                          lite = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_LITE)
                          student = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_STUDENT)
                          edu = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_EDUCATION)
                          cineware = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ENABLE_IN_CINEWARE)
                          mxOne = TestLicenses(capsuleLicense, ASSETLICENSETYPE.ONLY_IN_MAXONONE)
                  
                          print(f"In All: {inAll}, Subscription: {sub}, Perpetual: {perpetual}, Trial: {trial}, Lite: {lite}, Student: {student}, Education: {edu}, Cineware: {cineware}, Maxon One: {mxOne}")
                  
                  if __name__ == '__main__':
                      main()
                  

                  For 2024.4 I plan to simplify the asset ID retrieval from a capsule. So thanks for the question and sorry for the delay.
                  Cheers,
                  Maxime.

                  MAXON SDK Specialist

                  Development Blog, MAXON Registered Developer

                  J 1 Reply Last reply Reply Quote 1
                  • J
                    JohnThomas @m_adam
                    last edited by

                    @m_adam

                    Thanks for the response.

                    Going through the code you have the line

                    assetDescription = repository.FindLatestAsset(maxon.AssetTypes.NodeTemplate(), assetId, maxon.Id(), maxon.ASSET_FIND_MODE.LATEST)
                    

                    Looking at the sdk the NodeTemplate for AssetTypes first appears in 2024.2. Is there a way to tell if there is a Maxon One asset in 2023 or is this new functionality that isn't possible in older versions?

                    John Thomas

                    1 Reply Last reply Reply Quote 0
                    • M
                      m_adam
                      last edited by

                      Hi correct in the previous version, there was an issue in our parser so this symbol was not exposed to Python.

                      But you can add the next line before

                      maxon.AssetTypes.NodeTemplate = maxon.MAXON_DECLARATION("net.maxon.node.assettype.nodetemplate")
                      

                      Cheers,
                      Maxime.

                      MAXON SDK Specialist

                      Development Blog, MAXON Registered Developer

                      1 Reply Last reply Reply Quote 0
                      • J
                        JohnThomas
                        last edited by

                        Thanks for the response. I'll see if this does what I need it to

                        John Thomas

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