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

    Get active object after random value

    Cinema 4D SDK
    python r19
    3
    8
    1.3k
    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
      Wusiki
      last edited by Wusiki

      Hello everyone.
      There are a few classes.
      One for choosing an object in the CycleList.
      Two for choosing a random object via change c4d.userdata value
      One works fine. But when I choose a random object I need to click on the viewport to update showing object. How to update viewport without clicking?

      I also have tried on the random class:

       c4d.EventAdd()
                  c4d.CallCommand(12147, 12147)
                  c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
      

      It doesn't work.
      Object class:

       if (config['hideState'] == True): #hide selected object
                  for indexObjectHide in range (0, limit): #loop for geting all objects
                      if (indexObjectHide == self.userdataGroup[c4d.ID_USERDATA,userDataId]): #which object is selected
                          self.parentObject.GetChildren()[indexObjectHide].SetEditorMode(2)
                          self.parentObject.GetChildren()[indexObjectHide].SetRenderMode(2)
                      else:
                          self.parentObject.GetChildren()[indexObjectHide].SetEditorMode(1)
                          self.parentObject.GetChildren()[indexObjectHide].SetRenderMode(1)
      

      Random class:

      if (self.userdataGroup[c4d.ID_USERDATA,userDataId] == True): #If random button clicked
                  SubLists = [] #
                  for ListIndex in range (0,len(config['Random id'])):#config['Random id'] is var where I can point userdata ids ehich will be randomed
                      SubLists.append([config['Random id'][ListIndex]])
                  indexList = []
                  for indexEl in range (0,len(SubLists)): #Loop for each id
                      for id, bc in self.userdataGroup.GetUserDataContainer():
                          cycleBC = bc.GetContainer(c4d.DESC_CYCLE)
                          if (id == c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA, c4d.DTYPE_SUBCONTAINER,0), c4d.DescLevel(SubLists[indexEl][0]))):
                              for element in cycleBC: # get userdata data
                                  if (len(indexList) == indexEl):
                                      indexList.append([element[0]])
                                  else:
                                      indexList[indexEl].append(element[0])
                      self.userdataGroup[c4d.ID_USERDATA,SubLists[indexEl][0]] = randint(0,len(indexList[indexEl]) - 1) #Change userdata values
                  self.userdataGroup[c4d.ID_USERDATA,userDataId] = False
      

      You can see full code in the attached c4d file. Pls help me
      For better understanding what I want, watch the video:


      Experieces.c4d
      /////
      Seems I've understood why I get the issue. I put random class before object class and it works 'cause in this code, I get an active object before getting random value. But it is doesn't correct in point of view of the code. It's hierarhy disturbing. Ways to generate active object after generating random?

      1 Reply Last reply Reply Quote 0
      • S
        s_bach
        last edited by

        Hello and welcome,

        please use the Q&A system to mark your post as a question.

        Also, please use tags to inform us about which version of Cinema you are using.

        What do you mean with "hierarhy disturbing"? What do you mean with "generate active object after generating random"?

        Why is your user interface on the "Interface" null object and not the Python Tag itself? If your UI would be on the Python Tag, you could implement the tag's message() function to handle such user events properly.

        def message(id, data):
            if id == c4d.MSG_DESCRIPTION_COMMAND:
                buttonID = data['id']
                # check for user data
                if buttonID[0].id == c4d.ID_USERDATA:
                    # ceck button ID
                    if buttonID[1].id == 1:
                        print("button pressed")
        

        best wishes,
        Sebastian

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 0
        • W
          Wusiki
          last edited by

          @s_bach said in Get active object after random value:

          please use the Q&A system to mark your post as a question.
          Also, please use tags to inform us about which version of Cinema you are using.

          And...Done.

          @s_bach said in Get active object after random value:

          What do you mean with "hierarhy disturbing"? What do you mean with "generate active object after generating random"?

          "Hierarhy disturbing".
          Simply put, there is first func (where there are object details) and there is the second func which generate a random number, but data of active object stores in the first func. Need to execute the second func before first to make it works. But it doesn't right cause' it disturbs actions timeline. Right way is: First display object to the viewport, then generate random nimber after pressing button. But this code requires to run second func before first one.
          "generate active object after generating random"
          I think attached video link better speaks for me.

          @s_bach said in Get active object after random value:

          Why is your user interface on the "Interface" null object and not the Python Tag itself?

          Thanks. Need to try.

          1 Reply Last reply Reply Quote 0
          • W
            Wusiki
            last edited by

            I get the same issue. The script gives only previous data (randint limit). I know why, but I don't know how to get an active data.

            def message(id, data):
                if id == c4d.MSG_DESCRIPTION_COMMAND:
                    randomButtons = [5] #Random  buttons Ids
                    buttonID = data['id']
                    SubList = [] #container storing id's values to have to changing
                    SubList = randomId_new(SubList,[3,4])#filling the container
                    if buttonID[0].id == c4d.ID_USERDATA:#check for user data
                        for RandomButtonId in range (0,len(randomButtons)):#loop for each button
                            if buttonID[1].id == randomButtons[RandomButtonId]:#check button ID
                                for SublistId in range (0,len(SubList[RandomButtonId])):
                                    RandomLimit = 0 #limit for randint
                                    for id, bc in op.GetUserDataContainer():
                                        if (id == c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA, c4d.DTYPE_SUBCONTAINER,0), c4d.DescLevel(SubList[RandomButtonId][SublistId]))): #check id
                                            cycleBC = bc.GetContainer(c4d.DESC_CYCLE)
                                            for element in cycleBC: #define len of cycleList
                                                RandomLimit += 1
                                    op[c4d.ID_USERDATA,SubList[RandomButtonId][SublistId]] = randint(0,RandomLimit - 1) #generate random value
                                    print(str(SubList[RandomButtonId][SublistId]) + ': ' + str(RandomLimit)) #checking to console 
            

            You can see what I want via video

            1 Reply Last reply Reply Quote 0
            • ManuelM
              Manuel
              last edited by

              hello,

              Is it possible to have the last version of your file so i have a chance to follow you and try to help you.

              Cheers
              Manuel

              MAXON SDK Specialist

              MAXON Registered Developer

              1 Reply Last reply Reply Quote 0
              • W
                Wusiki
                last edited by

                @m_magalhaes said in Get active object after random value:

                hello,
                Is it possible to have the last version of your file so i have a chance to follow you and try to help you.

                Sure. Thanks in advance. I also commented on my code to better to understand.
                Experieces_old.c4d

                1 Reply Last reply Reply Quote 0
                • ManuelM
                  Manuel
                  last edited by

                  hello,

                  You create your UI dynamically but still use it to retrieves data. You should simply separate both.

                  The problem here is that Message() is called before Main() (nothing you can changed)

                  In the Message() function you can check the id == MSG_DESCRIPTION_POSTSETPARAMETER, you can retrieves the descid in the data attached.

                  By checking the descid you can update only if the cycles are changed. (not the button)

                  Your Main() can be "empty". I picked everything that was in Main() and copy/paste in LaunchUpdate()
                  You should split that function in several parts.

                  In the random function I can now call LaunchUpdate() to update the UI and use it to retrieves the data. (but as I said you should separate both)

                  This now works but LaunchUpdate() is executed too much times. It would need more work to split that function in several parts.

                  This look more like a design issue than a Cinema4D issue.

                  Let me know if i'm not clear.

                  import c4d
                  from c4d import gui
                  from c4d import documents
                  import random
                  from random import randint
                  
                  class bcSettings():
                      def Group(self,basecontainerVar,groupContainerVar,columns=1,parentGroupState=False,parentGroupId=0):
                          return {'Base container': basecontainerVar, 'Group container': groupContainerVar,'Columns': columns,'Subgroup': parentGroupState,'Parent group id': parentGroupId}
                      def CycleObj(self,basecontainerVar,groupContainerVar,parentGroupId=0,hide=True):
                          return {'Base container': basecontainerVar, 'Group container': groupContainerVar,'Parent group id': parentGroupId,'hideState': hide}
                      def CycleTex(self,basecontainerVar,groupContainerVar,effect,shader,parentGroupId=0):
                          return {'Base container': basecontainerVar, 'Group container': groupContainerVar,'effect': effect,'shader': shader,'Parent group id': parentGroupId}
                      def RandomButton (self,basecontainerVar,groupContainerVar,parentGroupId=0):
                          return {'Base container': basecontainerVar, 'Group container': groupContainerVar,'Parent group id': parentGroupId}
                  def BaseContainerVariable(index,typeName): #it's list func for checking and adding to list a new varaibale instead use one unique variable
                      if (len(index) == 0):
                          index.append(typeName + str(1))
                      else:
                          index.append(typeName + str(len(index) + 1))
                      return index
                  
                  class base_controllers(object):
                      def __init__(self,userdataGroup,parentObject=None):
                          self.userdataGroup = userdataGroup
                          self.parentObject = parentObject
                      def Group(self,config,title,userDataId):
                          BaseContainerVariable(config['Base container'],'BaseContainerId')
                          CountCheckingBC = 0
                          #check if list is null and add new varabe to list
                          if (len(config['Base container']) > 0):
                              CountCheckingBC = len(config['Base container']) - 1
                              config['Base container'][CountCheckingBC] = title + 'BaseContainer'
                              config['Base container'][CountCheckingBC] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_GROUP)
                          else:
                              config['Base container'][0] = title + 'BaseContainer'
                              config['Base container'][0] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_GROUP)
                          #continue creating userdata
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_NAME, title)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_SHORT_NAME, title)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_COLUMNS, config['Columns'])
                          if (config['Subgroup'] == True and config['Parent group id'] > 0 ): #check whether userdata should have a parent group
                              config['Base container'][CountCheckingBC].SetData(c4d.DESC_PARENTGROUP, c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(config['Parent group id'], c4d.DTYPE_GROUP, 0)))
                          BaseContainerVariable(config['Group container'],'GroupContainerId')
                          CountCheckingCont = 0
                          #check if list is null and add new varabe to list
                          if (len(config['Group container']) > 0):
                              CountCheckingCont = len(config['Group container']) - 1
                          config['Group container'][CountCheckingCont] = c4d.BaseContainer()
                          config['Base container'][CountCheckingBC].SetContainer(c4d.DESC_CYCLE, config['Group container'][CountCheckingCont])
                          self.userdataGroup.SetUserDataContainer([c4d.ID_USERDATA, userDataId], config['Base container'][CountCheckingBC])
                      def CycleObj(self,config,title,userDataId):
                          BaseContainerVariable(config['Base container'],'BaseContainerId')
                          CountCheckingBC = 0
                          #check if list is null and add new varabe to list
                          if (len(config['Base container']) > 0):
                              CountCheckingBC = len(config['Base container']) - 1
                              config['Base container'][CountCheckingBC] = title + 'BaseContainer'
                              config['Base container'][CountCheckingBC] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
                          else:
                              config['Base container'][0] = title + 'BaseContainer'
                              config['Base container'][0] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
                          #continue creating userdata
                          limit = len(self.parentObject.GetChildren())
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_NAME, title)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_SHORT_NAME, title)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_MIN, 0)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_MAX, limit-1)
                          config['Base container'][CountCheckingBC].SetData(c4d.DESC_PARENTGROUP, c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(config['Parent group id'], c4d.DTYPE_GROUP, 0)))
                          BaseContainerVariable(config['Group container'],'GroupContainerId')
                          CountCheckingCont = 0
                          if (len(config['Base container']) > 0):
                              CountCheckingCont = len(config['Group container']) - 1
                          config['Group container'][CountCheckingCont] = c4d.BaseContainer()
                          for indexLoop in range(0, limit):#filling userdata container with object names
                              config['Group container'][CountCheckingCont].SetString(indexLoop, self.parentObject.GetChildren()[indexLoop].GetName())
                          config['Base container'][CountCheckingBC].SetContainer(c4d.DESC_CYCLE, config['Group container'][CountCheckingCont])
                          self.userdataGroup.SetUserDataContainer([c4d.ID_USERDATA, userDataId], config['Base container'][CountCheckingBC])
                          if (config['hideState'] == True): #hide all objects besides chosen
                              for indexObjectHide in range (0, limit):
                                  if (indexObjectHide == self.userdataGroup[c4d.ID_USERDATA,userDataId]):
                                      self.parentObject.GetChildren()[indexObjectHide].SetEditorMode(2)
                                      self.parentObject.GetChildren()[indexObjectHide].SetRenderMode(2)
                                  else:
                                      self.parentObject.GetChildren()[indexObjectHide].SetEditorMode(1)
                                      self.parentObject.GetChildren()[indexObjectHide].SetRenderMode(1)
                      def CycleTex(self,config,title,userDataId):
                          layer_list = []
                          temp_list_var = config['shader'].GetFirstLayer()
                          layer_list.append(temp_list_var)
                          while temp_list_var:# get layers
                              if temp_list_var.GetNext() is not None:
                                  layer_list.append(temp_list_var.GetNext())
                                  temp_list_var = temp_list_var.GetNext()
                              else:
                                  break
                          count_texture = len(layer_list)
                          BaseContainerVariable(config['Base container'],'BaseContainerId')
                          CountCheckingBC = 0
                          if (len(config['Base container']) > 0):
                              CountCheckingBC = len(config['Base container']) - 1
                              config['Base container'][CountCheckingBC] = title + 'BaseContainer'
                              config['Base container'][CountCheckingBC] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
                          else:
                              config['Base container'][0] = title + 'BaseContainer'
                              config['Base container'][0] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_LONG)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_NAME, title)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_SHORT_NAME, title)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_CYCLE)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_MIN, 0)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_MAX, count_texture-1)
                          config['Base container'][CountCheckingBC].SetData(c4d.DESC_PARENTGROUP, c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(config['Parent group id'], c4d.DTYPE_GROUP, 0)))
                          BaseContainerVariable(config['Group container'],'GroupContainerId')
                          CountCheckingCont = 0
                          if (len(config['Base container']) > 0):
                              CountCheckingCont = len(config['Group container']) - 1
                          config['Group container'][CountCheckingCont] = c4d.BaseContainer()
                          if (config['effect'] == 'hide'):
                              for indexLoop in range(0, len(layer_list)):
                                  config['Group container'][CountCheckingCont].SetString(indexLoop, "Texture " + str(indexLoop + 1))
                          config['Base container'][CountCheckingBC].SetContainer(c4d.DESC_CYCLE, config['Group container'][CountCheckingCont])
                          self.userdataGroup.SetUserDataContainer([c4d.ID_USERDATA, userDataId], config['Base container'][CountCheckingBC])
                          if (config['effect'] == 'hide'):
                              active_texture = self.userdataGroup[c4d.ID_USERDATA,userDataId]
                              if (active_texture >= count_texture):
                                  self.userdataGroup[c4d.ID_USERDATA,userDataId] = count_texture - 1
                                  active_texture = self.userdataGroup[c4d.ID_USERDATA,userDataId]
                              for index_active_texture in range(0,count_texture):
                                  if (index_active_texture == active_texture):
                                      layer_list[index_active_texture].SetParameter(c4d.LAYER_S_PARAM_ALL_ACTIVE, True)
                                  else:
                                      layer_list[index_active_texture].SetParameter(c4d.LAYER_S_PARAM_ALL_ACTIVE, False)
                          c4d.EventAdd()
                          config['shader'].Message(c4d.MSG_CHANGE)
                      def RandomButton(self,config,title,userDataId):
                          BaseContainerVariable(config['Base container'],'BaseContainerId')
                          CountCheckingBC = 0
                          if (len(config['Base container']) > 0):
                              CountCheckingBC = len(config['Base container']) - 1
                              config['Base container'][CountCheckingBC] = title + 'BaseContainer'
                              config['Base container'][CountCheckingBC] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_BUTTON)
                          else:
                              config['Base container'][0] = title + 'BaseContainer'
                              config['Base container'][0] = c4d.GetCustomDatatypeDefault(c4d.DTYPE_BUTTON)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_NAME, title)
                          config['Base container'][CountCheckingBC].SetString(c4d.DESC_SHORT_NAME, title)
                          config['Base container'][CountCheckingBC].SetInt32(c4d.DESC_CUSTOMGUI, c4d.CUSTOMGUI_BUTTON)
                          config['Base container'][CountCheckingBC].SetData(c4d.DESC_PARENTGROUP, c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA), c4d.DescLevel(config['Parent group id'], c4d.DTYPE_GROUP, 0)))
                          BaseContainerVariable(config['Group container'],'GroupContainerId')
                          CountCheckingCont = 0
                          if (len(config['Base container']) > 0):
                              CountCheckingCont = len(config['Group container']) - 1
                          config['Group container'][CountCheckingCont] = c4d.BaseContainer()
                          config['Base container'][CountCheckingBC].SetContainer(c4d.DESC_CYCLE, config['Group container'][CountCheckingCont])
                          self.userdataGroup.SetUserDataContainer([c4d.ID_USERDATA, userDataId], config['Base container'][CountCheckingBC])
                  
                  def main():
                      pass
                     
                  
                  def LaunchUpdate():
                      Interface = op.GetObject()
                      Objects = Interface.GetDown()
                      indexBc = []
                      groupBc = []
                      InterfaceGroup = bcSettings().Group(indexBc,groupBc)
                      base_controllers(op,Objects).Group(InterfaceGroup,'Interface',1)
                      ObjectsGroup = bcSettings().Group(indexBc,groupBc,3,True,1)
                      base_controllers(op,Objects).Group(ObjectsGroup,'Objects',2)
                      ObjectsCycle = bcSettings().CycleObj(indexBc,groupBc,2,True)
                  
                      base_controllers(op,Objects).CycleObj(ObjectsCycle,'Object',3)
                      active_Ttag = Objects.GetChildren()[op[c4d.ID_USERDATA,3]].GetFirstTag()
                      active_Ttag = active_Ttag.GetNext()
                      active_mat = active_Ttag.GetMaterial()
                      if active_mat is None:
                          return
                      shader = active_mat[c4d.MATERIAL_COLOR_SHADER]
                      if shader is None:
                          return
                  
                      TextureCycle = bcSettings().CycleTex(indexBc,groupBc,'hide',shader,2)
                      base_controllers(op,Objects).CycleTex(TextureCycle,'Texture',4)
                      ObjectRandomButton = bcSettings().RandomButton(indexBc,groupBc,2)
                      base_controllers(op,Objects).RandomButton(ObjectRandomButton,'Random',5)
                  
                  def randomId_new(index,data):
                      index.append(data)
                      return index
                  
                  def message(id, data):
                      if id == c4d.MSG_DESCRIPTION_POSTSETPARAMETER:
                          print data['descid']
                              
                          LaunchUpdate()
                          
                      if id == c4d.MSG_DESCRIPTION_COMMAND:
                  
                          randomButtons = [5] #Random  buttons Ids
                          buttonID = data['id']
                          SubList = [] #container storing id's values to have to changing
                          SubList = randomId_new(SubList,[3,4])#filling the container
                          if buttonID[0].id == c4d.ID_USERDATA:#check for user data
                              for RandomButtonId in range (0,len(randomButtons)):#loop for each button
                                  if buttonID[1].id == randomButtons[RandomButtonId]:#check button ID
                                      for SublistId in range (0,len(SubList[RandomButtonId])):
                                          LaunchUpdate() # we can launch an update of the ui
                                          RandomLimit = 0 #limit for randint
                                          for id, bc in op.GetUserDataContainer():
                                              if (id == c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA, c4d.DTYPE_SUBCONTAINER,0), c4d.DescLevel(SubList[RandomButtonId][SublistId]))): #check id
                                                  cycleBC = bc.GetContainer(c4d.DESC_CYCLE)
                                                  for element in cycleBC: #define len of cycleList
                                                      RandomLimit += 1
                                          op[c4d.ID_USERDATA,SubList[RandomButtonId][SublistId]] = randint(0,RandomLimit - 1) #generate random value
                                          print(str(SubList[RandomButtonId][SublistId]) + ': ' + str(RandomLimit)) #checking to console
                          
                  

                  Cheers
                  Manuel

                  MAXON SDK Specialist

                  MAXON Registered Developer

                  1 Reply Last reply Reply Quote 1
                  • W
                    Wusiki
                    last edited by Wusiki

                    @m_magalhaes said in Get active object after random value:

                    The problem here is that Message() is called before Main() (nothing you can changed)

                    Hello.
                    Thank you so much. I've understood. Yea, it works. I'd break my mind to understand it by myself. So, then I gonna optimize drawcalls (don't know how to call it another) of LaunchUpdate() func

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