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
    1. Maxon Developers Forum
    2. ThomasB
    3. Posts
    • Profile
    • Following 1
    • Followers 0
    • Topics 32
    • Posts 110
    • Best 3
    • Controversial 0
    • Groups 0

    Posts made by ThomasB

    • RE: Maxon API for Python

      @ferdinand
      Thank you for your detailed explanation, it shed some light on the whole matter for me.

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • Maxon API for Python

      Apologies in advance if this question is out of scope.
      Is the Maxon API already fully usable for Python, or can it completely replace the classic API? I find it very difficult to understand right now. Or is it more intended for initializing data types and using it in conjunction with the classic API?
      And if not, when will it finally be fully usable for Python?

      posted in Cinema 4D SDK python 2025 windows
      ThomasBT
      ThomasB
    • RE: TempUVHandle always None! Why?

      @i_mazlov
      Thank you very much for the hint with the texture view and for the helpful links.
      The second thread I have already read, but was not able to find the solution so far. I study these examples. Thank you.

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • TempUVHandle always None! Why?

      Hi,
      I am not able to get the TempUVHandle from an active UVWTag in R21.
      It returns always "None".
      In the following script I created a simple plane in a TempDoc and took the cache and inserted it into the TempDoc. It already has a UVW-Tag, then I have set the object active and so the UVWTag....

      My Code:

      import c4d
      
      def main():
          temp = c4d.documents.BaseDocument()
      
          plane = c4d.BaseObject(c4d.Oplane)
          temp.InsertObject(plane)
          temp.ExecutePasses(bt=None, animation=False, expressions=False, caches=True, flags=c4d.BUILDFLAGS_NONE)
          
          plane_cache = plane.GetCache().GetClone()
      
          if plane_cache is None:
              raise Exception("no cache")
      
          temp.InsertObject(plane_cache)
          uvw_tag = plane_cache.GetTag(c4d.Tuvw)   
          temp.SetActiveTag(uvw_tag)
          temp.SetActiveObject(plane_cache)
      
          handle = c4d.modules.bodypaint.GetActiveUVSet(temp, c4d.GETACTIVEUVSET_UVWS)
          
          print(handle)
          
      
      # Execute main()
      if __name__=='__main__':
          main()
      
      posted in Cinema 4D SDK r21 python windows
      ThomasBT
      ThomasB
    • RE: Dynamically adding parameters in tag plugin - description is not refreshing

      @ferdinand
      Thanks a lot Ferdinand for your time and effort. It is always admirable how carefully and thoroughly you answer many questions.
      At first it was often difficult to understand and follow your code examples...now it is a little easier.
      Thanks for that.

      I found out that the following method also does the job:

      c4d.SendCoreMessage(c4d.COREMSG_CINEMA, c4d.BaseContainer(c4d.COREMSG_CINEMA_FORCE_AM_UPDATE), 0)
      

      Sorry for the second question about why this

      buttonDesc[c4d.DESC_FITH] = True
      buttonDesc[c4d.DESC_SCALEH] = True
      

      in the GetDDescription method are not working. I thought this is a follow-up question.
      I will open another topic for that.

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • Dynamically adding parameters in tag plugin - description is not refreshing

      Hi, in my object plugin it worked fine but in my tag plugin the description cannot be updated after clicking a button which in this example should add a new button.

      so when I click the button it adds a new id to the member variable self.id_list, and then I iter through this list in my GetDDescription() method
      It just shows the added Button if I click on the Object which holds the tag and select again the tag.
      Do I have to send a message? I read the GitHubExample but it is a example with an ObjectPlugin.

      import c4d
      from c4d import bitmaps, gui, plugins
      
      # Just a test ID
      PLUGIN_ID = 1110101
      
      PY_ADD_TRACK = 10000
      
      #The Plugin Class
      class Audioworkstation(plugins.TagData):
          def __init__(self):
              self.id_list = []
      
          def Init(self, node):       
              return True   
      
          def GetDDescription(self, op, description, flags):       
              if not description.LoadDescription(op.GetType()):
                  return False
              singleID = description.GetSingleDescID()
      
              # id_counter = 1
              for desc_id in reversed(self.id_list):
                 
                  measure_object_hide = c4d.DescID(c4d.DescLevel(desc_id + 2, c4d.DTYPE_BUTTON, op.GetType()))
                  if not singleID or measure_object_hide.IsPartOf(singleID)[0]:
                      bc_measure_object_hide = c4d.GetCustomDataTypeDefault(c4d.DTYPE_BUTTON)
                      bc_measure_object_hide[c4d.DESC_NAME] = "DELETE"
                      bc_measure_object_hide[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_BUTTON
                      # id_counter += 1
                      if not description.SetParameter(measure_object_hide, bc_measure_object_hide, c4d.DescID(c4d.DescLevel(
                                                          c4d.ID_TAGPROPERTIES))):
                          return False
      
              return True, flags | c4d.DESCFLAGS_DESC_LOADED
      
          def Execute(self, tag, doc, op, bt, priority, flags):
              return c4d.EXECUTIONRESULT_OK
      
          def Message(self, node, type, data):
      
              if type == c4d.MSG_DESCRIPTION_COMMAND:
                  if data["id"][0].id == PY_ADD_TRACK:
                     
                      last_id = None
                      if self.id_list:
                          last_id = self.id_list[-1]
                          new_id = last_id + 100
                          self.id_list.append(new_id)
                      else:
                          new_id = 10100
                          self.id_list.append(new_id)
                      node.Message(c4d.MSG_CHANGE)                
      
              return True
      
      # main
      if __name__ == "__main__":    
          bmp = bitmaps.BaseBitmap()
          dir, file = os.path.split(__file__)
          fn = os.path.join(dir, "res", "icon.tif")
          bmp.InitWith(fn)
          
          c4d.plugins.RegisterTagPlugin(id=PLUGIN_ID,
                                        str="C4D-Audioworkstation",
                                        info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE,
                                        description="audioworkstation",
                                        g=Audioworkstation, icon=bmp)
      
      

      edit by @ferdinand:

      @ThomasB said:

      I have also problems to scale the button so that it fits the attribute manager:

      so this doesn't work in the GetDDescription Example above:

      bc_measure_object_hide[c4d.DESC_SCALEH] = True
      bc_measure_object_hide[c4d.DESC_FITH] = True
      
      posted in Cinema 4D SDK r23 2023 2024 python windows
      ThomasBT
      ThomasB
    • RE: 2024.4.0 crashes when setting key-values

      @ferdinand
      this is really odd, because I have a Button in my plugin which simply creates keyframes for specific description parameters of the plugin, similar as it is in the PoseMorph Tag when you create keyframes for all sliders at once. And here it works without crashing:
      Maybe this helps you.
      The code of writing the keyframes is pretty the same, the only difference is that I set here keyframes for the description Id's instead of the user-datas...hm

      this is just a snippet:

      PY_STRENGTH_A_MANUAL = 10051
      PY_STRENGTH_E_MANUAL = 10052
      PY_STRENGTH_I_MANUAL = 10053
      PY_STRENGTH_O_MANUAL = 10054
      PY_STRENGTH_U_MANUAL = 10055
      PY_STRENGTH_F_MANUAL = 10056
      PY_STRENGTH_W_MANUAL = 10057
      PY_STRENGTH_SH_MANUAL = 10058
      PY_STRENGTH_OTHERS_MANUAL = 10059
      PY_STRENGTH_CLOSED_MANUAL = 10060
      
      id_list = [PY_STRENGTH_A_MANUAL,
                 PY_STRENGTH_E_MANUAL,
                 PY_STRENGTH_I_MANUAL,
                 PY_STRENGTH_O_MANUAL,
                 PY_STRENGTH_U_MANUAL,
                 PY_STRENGTH_F_MANUAL,
                 PY_STRENGTH_W_MANUAL,
                 PY_STRENGTH_SH_MANUAL,
                 PY_STRENGTH_OTHERS_MANUAL,
                 PY_STRENGTH_CLOSED_MANUAL
                 ]
      #========Plugin====================
              def Message(self, node, type, data):
                  if data["id"][0].id == PY_RECORD_MANUAL:
      
                      time = node.GetObject().GetDocument().GetTime()
                      node.GetDocument().AddUndo(c4d.UNDOTYPE_CHANGE, node)
                      if c4d.threading.GeIsMainThread():
                          for ide in id_list:
      
                              track = node.FindCTrack(ide)
      
                              if not track:
                                  track = c4d.CTrack(node, ide)
                                  node.InsertTrackSorted(track)
      
                              curve = track.GetCurve(c4d.CCURVE_CURVE, True)
      
                              keydata = curve.AddKey(time)
                              if keydata is None:
                                  raise RuntimeError("Could not add key frame.")
      
                              key = keydata["key"]
                              key.SetValue(curve, node[ide])
                              key[c4d.ID_CKEY_PRESET] = 2  # c4d.ID_CKEY_PRESET_AUTO_OVERSHOOTWEIGHTED
      
                      c4d.EventAdd()
      
      posted in Bugs
      ThomasBT
      ThomasB
    • 2024.4.0 crashes when setting key-values

      Hello,

      I'm just a bit stumped. In previous versions of C4D this approach, writing keys worked perfectly.
      Normally the routine is executed by a plugin in the message method, but I was able to change the example into a script and that's where the error occurs.

      Here I have the script and the required scene with the object.
      bake_test.zip

      The script should simply write keys with values ​​into the user data, usually the user datas are animated and they are a lot more, so in the plugin it has to filter the right ones
      After detailed debugging, I'm sure the error happens in the third last line with key.SetValue(curve, value)

      import c4d
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected opect in `doc`. Can be `None`.
      
      def bake():
      
          strength_list = {
              "AA": 1,
              "EE": 1,
              "IY": 1,
              "OW": 1,
              "UW": 1,
              "F": 1,
              "W": 1,
              "SH": 1,
              "T": 1,
              "M": 1
          }
      
          after_list = []
      
          # =================================================
      
          user_list = ["AA", "EE", "IY", "OW", "UW", "F", "W", "SH", "T", "M"]
      
          parameter_list = []
      
          for ide, bc in op.GetUserDataContainer():
              if bc[c4d.DESC_NAME] in user_list:
                  parameter_list.append(ide)
                  after_list.append(bc[c4d.DESC_NAME])
      
          if not parameter_list:  # if no userdatas added
              c4d.gui.MessageDialog("Missing User Datas!\n\nClick 'Add User-Data'")
              return True
      
          doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
          c4d.StatusSetSpin()
          # start = node[PY_BAKE_START]
          # end = node[PY_BAKE_END]
      
          for frame in range(0, 90):
      
              time = c4d.BaseTime(frame, doc.GetFps())
      
              doc.SetTime(time)
      
              doc.ExecutePasses(None, True, True, True,
                                c4d.BUILDFLAGS_NONE)  # False True False
      
              for ide in parameter_list:
                  track = op.FindCTrack(ide)
      
                  if track is None:
                      track = c4d.CTrack(op, ide)
                      op.InsertTrackSorted(track)
      
                  curve = track.GetCurve()
                  keyData = curve.AddKey(time)
      
                  if keyData is None:
                      raise RuntimeError("Could not add key frame.")
      
                  key = keyData["key"]
      
                  key.SetValue(curve, op[ide])
      
                  key[c4d.ID_CKEY_PRESET] = 2  # c4d.ID_CKEY_PRESET_AUTO_OVERSHOOTWEIGHTED
      
          c4d.StatusClear()
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          bake()
      
      
      if __name__ == '__main__':
          main()
      

      Cheers

      posted in Bugs 2024 python windows
      ThomasBT
      ThomasB
    • Snapping to a specific position of an object plugin's object chain

      An Object plugin returns an object chain with certain objects.
      But now I need a point at a very specific position of the object where other objects created in Cinema 4D can snap to it.

      I have or rather wanted to solve this by creating an internal polygon object that is placed in the object chain with a point, for example. I then made the point visually visible using the Draw method

      ObjectData.Draw(self, op, drawpass, bd, bh)
      

      However, the snapping does not work properly. If you're too close, nothing will snap. If the snapping radius is too small, nothing works.
      Am I completely on the wrong track or should I approach the whole thing differently? Sometimes there's just a lack of new things, and I can't always find everything in the Github examples...sometimes I have to laugh at myself, how stupid I want to start a spedific approach....

      Regards

      posted in Cinema 4D SDK windows r23 2023 2024 python
      ThomasBT
      ThomasB
    • RE: How do I get the cache of a cloner in an ObjectData Plugin

      @ferdinand
      oh man thanks I forgot this

      BaseDocument.ExecutePasses(bt=None, animation=False, expressions=False, caches=True, flags=c4d.BUILDFLAGS_NONE)
      

      I tried that before but it seems I have set the caches parameter wrong.
      Thank you very much....

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • How do I get the cache of a cloner in an ObjectData Plugin

      Hi, sorry for this as always dumb question.

      I was trying to get the Cache of a cloner object in the GetVirtualObjects(self, op, hh) method.
      First I tried it in the python generator, there was already a cloner in the scene and in the python generator I returned the cache so to say, but this approach doesn´t work out in an object plugin.
      Even if I create a temp_doc. The returned cache is always None.
      But converting the cloner with a ModelingCommand is not the best way, if the cloner produces for instance a million clones.

      This method works in a python generator when the clone is already in the scene

      cloner = op.GetDown()
      return cloner.GetCache().GetClone()
      

      But creating a cloner and returning its cache doesn`t work.

      cloner = c4d.BaseObject(1018544)
      c4d.BaseObject(c4d.Ocube).InsertUnder(cloner)
      return cloner.GetCache().GetClone()
      

      Is there a way to get the cache in a plugin?
      Sweep, Extrude, other Generators, Deformers and parametric objects work perfectly.

      posted in Cinema 4D SDK 2023 2024 r23 r25 python
      ThomasBT
      ThomasB
    • RE: Boole Object causes version 2024 to freeze

      @ferdinand
      Hello Ferdinand,
      Thank you very much first of all.
      yes, you're right, I worked extremely sloppily with the SMC method, of course I'll take the threading into account and also work with a Temp Document.

      Regarding the problem itself, I can only say that reinstalling CINEMA 4D solved our problem.

      Cheers

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • Boole Object causes version 2024 to freeze

      Hi,

      for demonstration purposes, I have an extremely stripped down version (1200 LOC) of my plugin (6000 LOC) here.
      Unfortunately it was not possible to insert the whole Pyp file here because the post can only be a maximum of 32767 characters long. That's why I only have sent the classes and functions that are not so important are without code.

      • Condition: the window bars must be activated. Error with Boole happens in the method
      def bar_cutter(op, obj, bars, fixed=False)
      

      Description:

      Of course, it is not technically perfect and in this version it is more of a prototype. I was able to narrow down the error to the Bars_Cutter() function. That's why I only included the bar_cutter method.

      • In this function I read specific points from the created frame and create a spline, which I throw into an Extrude and then convert to a polygon object. this extrude is used to cut the window bars.
      • I then create a Boole object and throw the previously created bars together with the extrude into the Boole object.

      Normally I also create a polygon object from the Boole object with SendModelingCommand() but to prove that the error comes from the Boole, I insert the Boole object directly under the window frames.


      Problem:

      The problem now is this. If you reduce the arch height of this arched window, the polygons will now intersect. The following usually happens (R23-2023). The bars then simply disappear. And the glass is no longer displayed correctly either. That's actually OK. The user immediately knows that something is intersected. (Watch Video)

      And in version 23-2023.2 this works, as can be seen in the video.
      But in version 2024 when the polygons intersect, Cinema 4d freezes.

      I have a short video to watch here.

      Also the version of the plugin in a zip file for R23-2023 and 2024 for easy reference.
      Boole-Problem.zip

      It actually only happens when the intersection of the intersected polygons creates a slightly deformed extruder.


      Question:

      Why does this freeze in 2024... Version and in R23-2023 not?


      Temporary Solution:

      I was now able to get around the problem by calculating the points of the extrude, how many there should be if Arch Subd has a certain value. When the polygon interesects, the extrude suddenly has more points. And I'll check that. If there are more, I simply don't create the Boole anymore. Then it works......

      For demonstration purposes, I only sent the content of the plugin, not the res, header and str files. These are then included in the plugin itself. I hope that's ok.

      class WindowHelper:
          def __init__(self):
              pass
      
          @staticmethod
          def create_tex_tags(op, name):
              tag = c4d.BaseTag(c4d.Ttexture)
              tag[c4d.TEXTURETAG_PROJECTION] = 6
              tag[c4d.ID_BASELIST_NAME] = name
              op.InsertTag(tag)
      
          @staticmethod
          def catch_tex_tag(op, name, goal):
              # new tag read from op
              frame_tag = None
              for tag in op.GetTags():
                  if tag.GetName().lower() == name:
                      frame_tag = tag
                      break
              if frame_tag is not None:
                  if goal:
                      goal.InsertTag(frame_tag.GetClone())
      
          @staticmethod
          def load_profile():
              # to less characters
      
          @staticmethod
          def set_handle_pos(op, frame, handle, f_type=1, w_type=1, h_pos=0):
             # to much characters
      
          @staticmethod
          def load_handle():
             # to much
      
          @staticmethod
          def load_sill():
              sill_path = os.path.join(path, "res", "b_al")
              sill = c4d.BaseObject(c4d.Ospline)
              c4d.storage.ReadHyperFile(None, sill, sill_path, 100)
              return sill
      
          @staticmethod
          def set_axis(op, pos):
              # to much
      
          @staticmethod
          def create_arch_spline(op, widtho, heighto, archo, subdo, multi=1, glass=False):
              # to much
              return spline
      
          def make_frames(self, node, f_spline, w_spline=None, pos=0, tilt=False, window_open=0):
      
              # to much
              return container
      
          @staticmethod
          def create_sill(op):
              # to much
              return extrude
      
          def make_sill(self, op):
              # to much
              return extrude
      
          @staticmethod
          def create_ring(op, radius=25, full_spiral=True, sub_d=8):
      
              tube = c4d.BaseObject(c4d.Otube)
              tube[c4d.PRIM_AXIS] = 5
              tube[c4d.PRIM_TUBE_ORAD] = radius
              if not full_spiral:
                  tube[c4d.PRIM_SLICE] = True
              tube[c4d.PRIM_TUBE_IRAD] = radius - op[PY_BAR_WIDTH]
              tube[c4d.PRIM_TUBE_SEG] = 4 * sub_d
              tube[c4d.PRIM_TUBE_HEIGHT] = 2 - 0.01
              tube[c4d.PRIM_TUBE_HSUB] = 1
              # pos = tube.GetRelPos() - c4d.Vector(0, 0, (2 - 0.01) / 2 + 0.01)
              # tube.SetRelPos(pos)
      
              tube: c4d.PolygonObject = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[tube],
                                                                      doc=op.GetDocument())[0]
              for tag in tube.GetTags():
                  if tag.IsInstanceOf(c4d.Tpolygonselection) or tag.IsInstanceOf(c4d.Tedgeselection):
                      tag.Remove()
      
              for index in range(len(tube.GetAllPoints())):
                  tube.SetPoint(index, tube.GetPoint(index) - c4d.Vector(0, 0, (2 - 0.01) / 2 + 0.01))
              return tube
      
          @staticmethod
          def create_bar(op, length, width, angle=0):
              """ Creates a bar with the length"""
      
              spline = c4d.SplineObject(4, c4d.SPLINETYPE_LINEAR)
              spline[c4d.SPLINEOBJECT_CLOSED] = True
      
              if angle == 0:
                  bar = c4d.BaseObject(c4d.Oextrude)
                  spline.SetPoint(0, c4d.Vector(-width / 2, 0, -.01))
                  spline.SetPoint(1, c4d.Vector(width / 2, 0, -.01))
                  spline.SetPoint(2, c4d.Vector(width / 2, 0, -2))
                  spline.SetPoint(3, c4d.Vector(-width / 2, 0, -2))
                  bar[c4d.EXTRUDEOBJECT_DIRECTION] = 2
                  bar[c4d.EXTRUDEOBJECT_EXTRUSIONOFFSET] = length
                  spline.InsertUnder(bar)
      
              elif angle == 90:
                  bar = c4d.BaseObject(c4d.Oloft)
                  bar[c4d.LOFTOBJECT_SUBX] = 4
                  bar[c4d.LOFTOBJECT_SUBY] = 2
                  bar[c4d.LOFTOBJECT_ADAPTIVEY] = False
                  spline.SetPoint(0, c4d.Vector(0, width / 2, -.01))
                  spline.SetPoint(1, c4d.Vector(0, -width / 2, -.01))
                  spline.SetPoint(2, c4d.Vector(0, -width / 2, -2))
                  spline.SetPoint(3, c4d.Vector(0, width / 2, -2))
                  spline2 = spline.GetClone()
                  spline.InsertUnder(bar)
                  spline2.InsertUnder(bar)
                  spline.SetRelPos(c4d.Vector(-length / 2, 0, 0))
                  spline2.SetRelPos(c4d.Vector(length / 2, 0, 0))
      
              bar.SetName("Bar")
      
              bar: c4d.PolygonObject = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[bar],
                                                                     doc=op.GetDocument())[0]
              for tag in bar.GetTags():
                  if tag.IsInstanceOf(c4d.Tpolygonselection) or tag.IsInstanceOf(c4d.Tedgeselection):
                      tag.Remove()
      
              return bar
      
          @staticmethod
          def bars_maker(op, width, height, method=0, fixed=False, bank=False, vert=0, hor=0, height2=0, count=2,
                         full_spiral=True):
              container = c4d.BaseObject(c4d.Onull)
              if fixed != 4:
                  pro_width = PROFILE_WIDTH
                  z = 4
              else:
                  pro_width = FIXED_PROFILE_WIDTH
                  z = 2.7
              bar_width = op[PY_BAR_WIDTH]
              if method == 0:
                  return None
              elif method == 1:
                  # if not fixed:
                  offset_vert = (width - 2 * pro_width) / (vert + 1)
      
                  if not bank:
                      offset_hor = (height - 2 * pro_width) / (hor + 1)
                  else:
                      offset_hor = (height + SILL_HEIGHT - 2 * pro_width) / (hor + 1)
      
                  for index in range(vert):
                      pos_x = pro_width + (index + 1) * offset_vert
      
                      length = height
                      bar = WindowHelper().create_bar(op, length=length, width=bar_width)
                      bar.InsertUnder(container)
      
                      bar.SetRelPos(c4d.Vector(pos_x, 0, z))
      
                  # horizontal length calc inside arch
      
                  for index in range(hor):
                      pos_y = pro_width + ((index + 1) * offset_hor)
                      length = width
                      bar = WindowHelper().create_bar(op, length=length, width=bar_width, angle=90)
                      bar.InsertUnder(container)
                      bar.SetRelPos(c4d.Vector(width / 2, pos_y, z))
      
                  return container
      
              elif method == 2:
                  if bank:
                      y = SILL_HEIGHT
                  else:
                      y = 0
                  offset_vert = (width - 2 * pro_width) / (vert + 1)
                  offset_vert2 = (width - 2 * pro_width) / (hor + 1)
      
                  bar_middle = WindowHelper().create_bar(op, length=width, width=bar_width, angle=90)
                  bar_middle.InsertUnder(container)
                  bar_middle.SetRelPos(c4d.Vector(width / 2, height2 + y, z))
      
                  for index in range(vert):
                      pos_x_bottom = pro_width + (index + 1) * offset_vert
                      length = height2 - bar_width / 2
                      bar = WindowHelper().create_bar(op, length=length + y, width=bar_width)
                      bar.InsertUnder(container)
                      bar.SetRelPos(c4d.Vector(pos_x_bottom, 0, z))
      
                  for index in range(hor):
                      pos_x_top = pro_width + (index + 1) * offset_vert2
                      length = height - height2 - bar_width / 2
                      bar = WindowHelper().create_bar(op, length=length, width=bar_width)
                      bar.InsertUnder(container)
                      bar.SetRelPos(c4d.Vector(pos_x_top, height2 + y + bar_width / 2, z))
      
                  return container
      
              elif method == 3:
                  radius = height2
                  if hor == 0:
                      sub_d = 1
                  else:
                      sub_d = hor * 3
      
                  if full_spiral:
                      y_pos = height / 2
                  else:
                      if fixed != 4:
                          y_pos = PROFILE_WIDTH - 1
                      else:
                          y_pos = FIXED_PROFILE_WIDTH
      
                  ring = WindowHelper().create_ring(op, radius=radius, full_spiral=full_spiral, sub_d=sub_d)
      
                  ring.InsertUnder(container)
                  ring.SetRelPos(c4d.Vector(width / 2, y_pos, z))
      
                  bar_boole = c4d.BaseObject(c4d.Oboole)
                  bar_boole[c4d.BOOLEOBJECT_SINGLE_OBJECT] = True
                  bar_boole[c4d.BOOLEOBJECT_HIDE_NEW_EDGES] = True
      
                  bar_cutter = c4d.BaseObject(c4d.Ocylinder)
                  bar_cutter[c4d.PRIM_AXIS] = 5
                  if not full_spiral:
                      bar_cutter[c4d.PRIM_SLICE] = True
                  bar_cutter[c4d.PRIM_CYLINDER_HSUB] = 1
                  bar_cutter[c4d.PRIM_CYLINDER_SEG] = 4 * sub_d
                  bar_cutter[c4d.PRIM_CYLINDER_RADIUS] = radius
      
                  bar_container = c4d.BaseObject(c4d.Onull)
                  if width > height:
                      length = width
                  else:
                      length = height
                  if full_spiral:
      
                      if count <= 2:
                          # create the spiral bars
      
                          bar = WindowHelper().create_bar(op, length=length, width=bar_width, angle=0)
                          bar_2 = bar.GetClone()
                          bar.InsertUnder(bar_container)
                          bar_2.InsertUnder(bar_container)
                          if count <= 1:
                              bar.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(90)))
                              bar_2.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(-90)))
                          else:
                              bar.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(0)))
                              bar_2.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(180)))
      
                      else:
                          angle_adder = 360.0 / count
                          angle = 90 - angle_adder
                          for index in range(count):
                              bar = WindowHelper().create_bar(op, length=length, width=bar_width, angle=0)
                              bar.InsertUnder(bar_container)
      
                              bar.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(angle + abs(angle_adder - 90))))
                              angle += angle_adder
      
                          if count > 4:
                              bar_container.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(180)))
                  else:
      
                      if count < 1:
                          count = 1
                      angle_adder = 180.0 / (count + 1)
                      angle = 0 + angle_adder
                      for index in range(count):
                          bar = WindowHelper().create_bar(op, length=length, width=bar_width, angle=0)
                          bar.InsertUnder(bar_container)
      
                          bar.SetRelRot(c4d.Vector(0, 0, c4d.utils.DegToRad(angle - 90)))
                          angle += angle_adder
      
                  bar_cutter.InsertUnder(bar_boole)
                  bar_container.InsertUnder(bar_boole)
                  bar_boole.InsertUnder(container)
                  bar_boole.SetRelPos(c4d.Vector(width / 2, y_pos, z))
      
                  return container
      
          @staticmethod
          def bar_cutter(op, obj, bars, fixed=False):
              normal = False
              direction = 5
              if fixed != 4:
                  frame: c4d.BaseObject = obj.GetDown().GetDown().GetDown()
                  numbers = frame.GetPointCount() // 21
                  points_list = []
                  start = CUTTER_POS
                  for point in range(numbers):
                      points_list.append(frame.GetPoint(start))
                      start += 21
              else:
                  # print(obj.GetDown())
                  direction = 5
                  normal = False
                  frame: c4d.BaseObject = obj.GetDown()
                  numbers = frame.GetPointCount() // 12
                  points_list = []
                  start = FIXED_CUTTER_POS
                  for point in range(numbers):
                      points_list.append(frame.GetPoint(start))
                      start += 12
      
              glass_spline = c4d.SplineObject(len(points_list), type=c4d.SPLINETYPE_LINEAR)
              glass_spline.SetAllPoints(points_list)
              glass_spline[c4d.SPLINEOBJECT_CLOSED] = True
              extrude = c4d.BaseObject(c4d.Oextrude)
              extrude[c4d.EXTRUDEOBJECT_FLIPNORMALS] = normal
              extrude[c4d.EXTRUDEOBJECT_EXTRUSIONOFFSET] = direction
              extrude.SetName("Glass")
              glass_spline.InsertUnder(extrude)
      
              # doc = c4d.documents.BaseDocument()
              # doc.InsertObject(extrude)
              # extrude = doc.GetFirstObject()
      
              extrude: c4d.PolygonObject = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                                                         list=[extrude.GetClone()],
                                                                         doc=op.GetDocument())[0]
      
              for tag in extrude.GetTags():
                  if tag.IsInstanceOf(c4d.Tpolygonselection) or tag.IsInstanceOf(c4d.Tedgeselection):
                      tag.Remove()
      
              boolen = c4d.BaseObject(c4d.Oboole)
              boolen[c4d.BOOLEOBJECT_TYPE] = 2
              boolen[c4d.BOOLEOBJECT_SINGLE_OBJECT] = True
              boolen[c4d.BOOLEOBJECT_BREAK_CUT_EDGES] = True
      
              if not bars.GetDown():
                  bars = c4d.BaseObject(c4d.Onull)
                  bars.SetName("Bars")
                  bars.InsertUnder(frame)
              else:
                  bars.InsertUnder(boolen)
                  extrude.InsertUnder(boolen)
      
                  # doc = c4d.documents.BaseDocument()
                  # doc.InsertObject(boolen)
                  # bars = doc.GetFirstObject().GetClone()
      
                  # bars: c4d.BaseObject = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                  #                                                      list=[boolen],
                  #                                                      doc=op.GetDocument())[0]
                  #
                  # if not bars.IsInstanceOf(c4d.Oboole):
                  #     bars.SetPhong(True, anglelimit=True, angle=c4d.utils.DegToRad(40))
                  #
                  #     bars.SetName("Bars")
                  #     for tag in bars.GetTags():
                  #         if tag.IsInstanceOf(c4d.Tedgeselection):
                  #             tag.Remove()
                  #     WindowHelper().catch_tex_tag(op, "bars", bars)
                  #
                  #     bars.InsertUnder(frame)
      
                  WindowHelper().catch_tex_tag(op, "bars", boolen)
                  boolen.InsertUnder(frame)
      
      
      
      
          def window_arch(self, op):
              container = c4d.BaseObject(c4d.Onull)
              # self.create_arch_window(op)
      
              spline = self.create_arch_spline(op, op[PY_WINDOW_WIDTH], op[PY_WINDOW_HEIGHT],
                                               op[PY_ARCH_HEIGHT],
                                               op[PY_ARCH_SUBD], multi=1.5)
      
              w_spline = self.create_arch_spline(op, op[PY_WINDOW_WIDTH], op[PY_WINDOW_HEIGHT],
                                                 op[PY_ARCH_HEIGHT],
                                                 op[PY_ARCH_SUBD], multi=.95)
              frames = self.make_frames(op, spline, w_spline, op[PY_WINDOW_DIRECTION], tilt=op[PY_TILT_CHECK],
                                        window_open=op[PY_WINDOW_OPEN])
      
              # glass creation
              self.preshious_glass(op, frames)
      
              # handle creation
              handle = self.handle.GetClone()
              WindowHelper().catch_tex_tag(op, "handle", handle)  # Mats for handle
              handle.InsertUnder(frames.GetDown().GetDown().GetDown())
      
              # test new handel function
              self.set_handle_pos(op, frames, handle, w_type=1, h_pos=op[PY_WINDOW_DIRECTION])
      
              # new bars IDs =========================================
              if op[PY_1BARS_LEFT] > 0:
                  if op[PY_1BARS_LEFT] == 1:
                      # Grid
                      bars_container = self.bars_maker(op, width=op[PY_WINDOW_WIDTH],
                                                       height=op[PY_WINDOW_HEIGHT],
                                                       method=op[PY_1BARS_LEFT],
                                                       bank=op[PY_BANK],
                                                       vert=op[PY_1BARS_LEFTVERT],
                                                       hor=op[PY_1BARS_LEFTHOR],
                                                       height2=op[PY_1BARS_LEFTMETHOD2DISTANCE],
                                                       )
      
                  elif op[PY_1BARS_LEFT] == 2:
                      # Dual Grid
                      bars_container = self.bars_maker(op, width=op[PY_WINDOW_WIDTH],
                                                       height=op[PY_WINDOW_HEIGHT],
                                                       method=op[PY_1BARS_LEFT],
                                                       bank=op[PY_BANK],
                                                       vert=op[PY_1BARS_LEFTDUALVERT],
                                                       hor=op[PY_1BARS_LEFTDUALHOR],
                                                       height2=op[PY_1BARS_LEFTMETHOD2DISTANCE],
                                                       count=op[PY_1BARS_LEFTVERT])
      
                  elif op[PY_1BARS_LEFT] == 3:
                      # Star
                      bars_container = self.bars_maker(op, width=op[PY_WINDOW_WIDTH], height=op[PY_WINDOW_HEIGHT],
                                                       method=op[PY_1BARS_LEFT],
                                                       bank=op[PY_BANK],
                                                       vert=op[PY_1BARS_LEFTSTARSTREAKS],
                                                       hor=op[PY_1BARS_LEFTSTARSUBD],
                                                       height2=op[PY_1BARS_LEFTSTARRADIUS],
                                                       count=op[PY_1BARS_LEFTSTARSTREAKS])
      
                  self.bar_cutter(op, frames, bars_container)
                  # bars_container = frames.GetDown().GetDown().GetDown().GetDown()
                  # if bars_container.IsInstanceOf(c4d.Oboole):
                  #     bars_container.Remove()
      
      
              # Bars End ==========================================================
      
              if op[PY_BANK]:
                  # sill = self.make_sill(op)
                  sill = self.create_sill(op)
                  sill.InsertUnder(frames.GetDown())
      
              frames.InsertUnder(container)
      
              if op[PY_OFFSET] is not None:
                  window = container.GetDown().GetDown()#.GetClone()
                  window.SetRelPos(c4d.Vector(0, 0, op[PY_OFFSET]))
      
              return container
      
          @staticmethod
          def preshious_glass(op, obj, fixed=0, toplightarch=False):
              direction = 1.5
              normal = False
              if fixed != 4:
                  if toplightarch:
                      direction = -1.5
                      normal = True
                  else:
                      direction = 1.5
                      normal = False
      
                  frame: c4d.BaseObject = obj.GetDown().GetDown().GetDown()
                  numbers = frame.GetPointCount() // 21
                  points_list = []
                  start = 7
                  for point in range(numbers):
                      points_list.append(frame.GetPoint(start))
                      start += 21
              else:
                  # print(obj.GetDown())
                  direction = 1.5
                  normal = False
                  frame: c4d.BaseObject = obj.GetDown()
                  numbers = frame.GetPointCount() // 12
                  points_list = []
                  start = 4
                  for point in range(numbers):
                      points_list.append(frame.GetPoint(start))
                      start += 12
      
              glass_spline = c4d.SplineObject(len(points_list), type=c4d.SPLINETYPE_LINEAR)
      
              glass_spline.SetAllPoints(points_list)
              glass_spline[c4d.SPLINEOBJECT_CLOSED] = True
              extrude = c4d.BaseObject(c4d.Oextrude)
              extrude[c4d.EXTRUDEOBJECT_FLIPNORMALS] = normal
              extrude[c4d.EXTRUDEOBJECT_EXTRUSIONOFFSET] = direction
              extrude.SetName("Glass")
              glass_spline.InsertUnder(extrude)
              extrude: c4d.PolygonObject = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                                                         list=[extrude],
                                                                         doc=op.GetDocument())[0]
      
              for tag in extrude.GetTags():
                  if tag.IsInstanceOf(c4d.Tpolygonselection) or tag.IsInstanceOf(c4d.Tedgeselection):
                      tag.Remove()
      
              WindowHelper().catch_tex_tag(op, "glass", extrude)
      
              extrude.InsertUnder(frame)
      
          def desc_arch(self, op, single_id, description, flags):
              arch_height = c4d.DescID(PY_ARCH_HEIGHT)  # using ID from above post
              height = c4d.DescID(PY_WINDOW_HEIGHT)
              width = c4d.DescID(PY_WINDOW_WIDTH)
      
              # Begrenzung =======================================
      
              if single_id is None or width.IsPartOf(single_id)[0]:
                  db = description.GetParameterI(width)
      
                  width_limiter = PROFILE_WIDTH * 2
      
                  db.SetFloat(c4d.DESC_MIN, width_limiter)
      
              if op[PY_ARCH_HEIGHT] is not None:
                  if single_id is None or height.IsPartOf(single_id)[0]:
                      db2 = description.GetParameterI(PY_WINDOW_HEIGHT)
                      width_limiter = op[PY_WINDOW_WIDTH] / 1
      
                      db2.SetFloat(c4d.DESC_MIN, op[PY_ARCH_HEIGHT] + width_limiter)
      
              # Hiding the Bars
              vert = c4d.DescID(PY_1BARS_LEFTVERT)
              hor = c4d.DescID(PY_1BARS_LEFTHOR)
              vert2 = c4d.DescID(PY_1BARS_LEFTDUALVERT)
              hor2 = c4d.DescID(PY_1BARS_LEFTDUALHOR)
              radius = c4d.DescID(PY_1BARS_LEFTSTARRADIUS)
              height = c4d.DescID(PY_1BARS_LEFTMETHOD2DISTANCE)
              streaks = c4d.DescID(PY_1BARS_LEFTSTARSTREAKS)
              segments = c4d.DescID(PY_1BARS_LEFTSTARSUBD)
      
              # left segment
              if single_id is None or vert.IsPartOf(single_id)[0]:
                  vert_bc = description.GetParameterI(PY_1BARS_LEFTVERT)
                  if op[PY_1BARS_LEFT] != 1:
                      vert_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or hor.IsPartOf(single_id)[0]:
                  hor_bc = description.GetParameterI(PY_1BARS_LEFTHOR)
                  if op[PY_1BARS_LEFT] != 1:
                      hor_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or vert2.IsPartOf(single_id)[0]:
                  vert2_bc = description.GetParameterI(PY_1BARS_LEFTDUALVERT)
                  if op[PY_1BARS_LEFT] != 2:
                      vert2_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or hor2.IsPartOf(single_id)[0]:
                  hor2_bc = description.GetParameterI(PY_1BARS_LEFTDUALHOR)
                  if op[PY_1BARS_LEFT] != 2:
                      hor2_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or streaks.IsPartOf(single_id)[0]:
                  streaks_bc = description.GetParameterI(PY_1BARS_LEFTSTARSTREAKS)
                  if op[PY_1BARS_LEFT] != 3:
                      streaks_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or segments.IsPartOf(single_id)[0]:
                  segments_bc = description.GetParameterI(PY_1BARS_LEFTSTARSUBD)
                  if op[PY_1BARS_LEFT] != 3:
                      segments_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or radius.IsPartOf(single_id)[0]:
                  radius_bc = description.GetParameterI(PY_1BARS_LEFTSTARRADIUS)
                  if op[PY_1BARS_LEFT] != 3:
                      radius_bc.SetBool(c4d.DESC_HIDE, True)
              if single_id is None or height.IsPartOf(single_id)[0]:
                  height_bc = description.GetParameterI(PY_1BARS_LEFTMETHOD2DISTANCE)
                  if op[PY_1BARS_LEFT] == 0 or op[PY_1BARS_LEFT] == 3:
                      height_bc.SetBool(c4d.DESC_HIDE, True)
      
      
      class Windows2023(plugins.ObjectData, WindowHelper):
      
          def __init__(self):
              self.SetOptimizeCache(True)
              self.profile = self.load_profile()
              self.handle = self.load_handle()
              self.sill = self.load_sill()
      
          def Init(self, op, isCloneInit):
      
              # Global Paramters
              self.InitAttr(op, bool, PY_BANK)
              self.InitAttr(op, float, PY_BANK_SIZE)
              self.InitAttr(op, float, PY_BANK_INNERSIZE)
              self.InitAttr(op, float, PY_BAR_WIDTH)
      
              # Arch Window Paramters
      
              self.InitAttr(op, float, PY_ARCH_HEIGHT)
              self.InitAttr(op, int, PY_ARCH_SUBD)
              self.InitAttr(op, bool, PY_TILT_CHECK)
              self.InitAttr(op, float, PY_WINDOW_OPEN)
              self.InitAttr(op, bool, PY_WINDOW_DIRECTION)
              self.InitAttr(op, bool, PY_ARCH_POINTED)
              self.InitAttr(op, bool, PY_ARCH_FIXER)
              self.InitAttr(op, float, PY_ARCH_STRENGTH)
      
              # Bars Arch left
              self.InitAttr(op, int, PY_1BARS_LEFT)
              self.InitAttr(op, int, PY_1BARS_LEFTVERT)
              self.InitAttr(op, int, PY_1BARS_LEFTHOR)
              self.InitAttr(op, float, PY_1BARS_LEFTMETHOD2DISTANCE)
              self.InitAttr(op, float, PY_1BARS_LEFTSTARRADIUS)
              self.InitAttr(op, int, PY_1BARS_LEFTDUALVERT)
              self.InitAttr(op, int, PY_1BARS_LEFTDUALHOR)
              self.InitAttr(op, int, PY_1BARS_LEFTSTARSTREAKS)
              self.InitAttr(op, int, PY_1BARS_LEFTSTARSUBD)
      
              if not isCloneInit:
      
                  # Global Parameters
                  op[PY_WINDOW_LIST] = 1
                  op[PY_WINDOW_WIDTH] = 100
                  op[PY_WINDOW_HEIGHT] = 120
      
                  op[PY_BANK] = False
                  op[PY_BANK_SIZE] = 0.0
                  op[PY_BANK_INNERSIZE] = 0.0
                  op[PY_BAR_WIDTH] = 2.0
      
                  # Arch Window
                  op[PY_WINDOW_SEGMENTS] = False
                  op[PY_ARCH_POINTED] = False
                  op[PY_ARCH_FIXER] = False
                  op[PY_ARCH_STRENGTH] = 30
                  op[PY_ARCH_HEIGHT] = 20
                  op[PY_ARCH_SUBD] = 8
                  op[PY_TILT_CHECK] = False
                  op[PY_WINDOW_OPEN] = 0.0
                  op[PY_WINDOW_DIRECTION] = False
      
                  # Bars Arch Window left
                  op[PY_1BARS_LEFT] = 0
                  op[PY_1BARS_LEFTVERT] = 1
                  op[PY_1BARS_LEFTHOR] = 1
                  op[PY_1BARS_LEFTMETHOD2DISTANCE] = 50
                  op[PY_1BARS_LEFTSTARRADIUS] = 20
                  op[PY_1BARS_LEFTDUALVERT] = 3
                  op[PY_1BARS_LEFTDUALHOR] = 1
                  op[PY_1BARS_LEFTSTARSTREAKS] = 4
                  op[PY_1BARS_LEFTSTARSUBD] = 2
      
              # op[c4d.MSG_CHANGE]
              return True
      
          def Message(self, node, type, data):
      
              if type == c4d.MSG_MENUPREPARE:
                  self.create_tex_tags(node, "Sill")
                  self.create_tex_tags(node, "Handle")
                  self.create_tex_tags(node, "Bars")
                  self.create_tex_tags(node, "Glass")
                  self.create_tex_tags(node, "Frame")
      
              return True
      
          def GetVirtualObjects(self, op, hh):
              # dirty = True if a cache is dirty or if the data (any parameters) of the object changed.
              # If nothing changed and a cache is present, return the cache
      
              # cache deaktiveren
      
              # dirty = op.CheckCache(hh) or op.IsDirty(c4d.DIRTYFLAGS_DESCRIPTION)
              # if not dirty:
              #     return op.GetCache(hh)
      
              return self.window_arch(op)
      
          def GetDDescription(self, op, description, flags):
      
              if not description.LoadDescription(op.GetType()):
                  return False
      
              single_id = description.GetSingleDescID()
      
              # Window 1 : Arch Window ==========================
              if op[PY_WINDOW_LIST] == 1:
                  self.desc_arch(op, single_id, description, flags)
      
              return True, flags | c4d.DESCFLAGS_DESC_LOADED
      
          def GetDEnabling(self, op, did, t_data, flags, itemdesc):
      
              # Window 1: Arch Window
              if op[PY_WINDOW_LIST] == 1:
                  if did[0].id == PY_1BARS_LEFTMETHOD2DISTANCE:
                      if op[PY_1BARS_LEFT] <= 1:
                          return False
      
              return True

      posted in Cinema 4D SDK r23 2023 2024 python windows
      ThomasBT
      ThomasB
    • RE: Object Plugin - Generator Objects - Hiding the child objects in Editor View

      @m_adam
      Thank you very much Maxime.
      But there is one more thing I would like to know.
      Why don't the highlighted links work? I am always referred to this site.

      not found.png

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • RE: Python: Detect Plugins

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

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • RE: Object Plugin - Generator Objects - Hiding the child objects in Editor View

      @CJtheTiger
      thanks
      But that doesn't seem to work because if, for example, I create an object plug-in that returns a cube in the GetVirtualObjects() method and I assign 2 objects to this plug-in in the Object Manager, then I still see the child objects in the editor window.

      Do I have to set a parameter or a flag somewhere to specify the ObjectPlugin somehow?

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • RE: OpenUSD (pxr) library in c4d python

      @llealloo
      That wasn't a one-way ticket recommendation, but just to test whether the problem still exists...😊

      I can't even get the usd library installed. pip shows me errors even via venv in pycharm as well as with their .whl files.

      Back to your proplem:

      • Maybe it doesn't work properly because the USD module needs some dependencies that are not installed or some modules are not supported in C4D python...to my knowledge not all modules of the standard library are supported in c4d python
      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • Object Plugin - Generator Objects - Hiding the child objects in Editor View

      Hi,
      Happy New Year

      I have an internal development question.

      How does this work, for example with Generators such as the Boole Object or Spline-Mask, when two objects are under the Bool-Object as childs, but these are no longer visible in their original form in the Editor View? But only the newly created object. They have to be hidden somehow but they are still visible in the Object Manager.

      • How does this work exactly?
      • Does this happen when registering the plugin with the method and specifying the info argument and type
      plugins.RegisterObjectPlugin(info=type))
      
      • Or do they have to be saved in a variable and deleted somehow or is there a Function to make them invisible?

      Just to get the idea?

      posted in Cinema 4D SDK windows r23 python 2023
      ThomasBT
      ThomasB
    • RE: OpenUSD (pxr) library in c4d python

      @llealloo
      Your link is not working, with the folder example in your first post.
      Have you tried to place it into a separate folder in your res-folder or directly into your plugin folder and write the path into to the sys-path?
      That's just a few lines of code:

      Folder structure:

      • plugin folder.
        • res folder
        • your module
        • plugin.pyp
      import os
      import sys
      
      # if the module is placed directly into the plugin folder - add the folder to the python search path
      folder = os.path.dirname(__file__)  # your plugin folder
      if folder not in sys.path:
          sys.path.insert(0, folder)
      
      import yourmodule
      

      But I would paste the module into the res-folder

      Folder structure:

      • plugin folder.
        • res folder
          • your module
        • plugin.pyp
      import os
      import sys
      
      # add the  res  folder to the python search path
      folder = os.path.join(os.path.dirname(__file__), "res")  # res folder
      if folder not in sys.path:
          sys.path.insert(0, folder)
      
      import yourmodule
      
      posted in Cinema 4D SDK
      ThomasBT
      ThomasB
    • RE: How to create python plugin in 2024?

      Yes, download the SDK and study the examples.
      I wrote my own software that allows me to simply select the type of plugin I want to create, enter the plugin ID and the plugin name. The program then creates the folder structure, all files with the correct content and the correct name automatically...that was the first thing I did because it is always extremely tedious.
      This then takes 10 seconds and I have a finished blueprint. Then I can start programming straight away.
      I usually make the Gui first using UserData to roughly create the design and then I write it down in the resfile in no time at all. It's relatively quick and even fun and you gradually grow into it, it emerges little by little.....

      Basically it wouldn't be a problem to write a script that writes the UserData interface into a Res, header and string file, I already have an idea for that... That would actually be easy to do.
      I'll get to it when I'm done with my update... and then maybe make it available to the community... However, a similar one is already there, but I can't remember where.

      Greetings
      Tom

      posted in Cinema 4D SDK
      ThomasBT
      ThomasB