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

    Tag plugin general issues (crash, threading, message)

    Cinema 4D SDK
    r23 2023 python windows
    2
    4
    630
    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.
    • ThomasBT
      ThomasB
      last edited by ThomasB

      Hello 😭,
      at the moment I try to create a tag plugin but it seems it is a bit more complicated than with an object plugin :-).

      I added a small snippet of the plugin as testtrans.zip zipfile.
      In the res-folder is the Cinema4d scene file (crashes) and a json-file.

      In the layout res-file I created a simple Baselink, Filename , Button(I want avoid) and BaseTime

      Function of the test plugin:

      • The user has to drag a pose morph tag into the Baselink.
      • Then he has to load the json1.json file as link

      The user loads the *.json file (res-folder), I catch this via c4d.MSG_DESCRIPTION_POSTSETPARAMETER and this triggers the function load_transcript() and loads the *.json file content into a member variable self.data.

      Questions:

      • Main Question: In the Execute(self, tag, doc, op, bt, priority, flags) method I want to to some actions. But here Cinema is crashing. Probably it has something to do with threading and that it asks the tags description.:-).
        I commented out the position where it is crashing. So if I replace the tag[PY_SYNC_START] simply with an integer it works

      • Is the method I used in the Message() method correct to detect the changes in the filename link? It doesn't work so I added a button to load it , then it works, but I want it to load as soon as the user changes the link to the json file. It calls the print() function in the POSTSETPARAMETER thing, but it doesn't trigger the load_transfile() method.

      • Another small bug maybe in Cinema 4D. When I set the ACCEPT parameter in the Baselink in the res-file to {Tposemorph;} he gives me a ressource error but when I type Tdisplay it works ??????

      Here is the code:

      import c4d
      import os
      from c4d import bitmaps, gui, plugins
      import json
      
      # be sure to use a unique ID obtained from www.plugincafe.com
      PLUGIN_ID = 5554443  # just a test ID
      
      # ID's
      PY_MORPH_LINK = 10000
      PY_TRANSCRIPT_LINK = 10001
      PY_SYNC_START = 10018
      PY_LOAD_TRANSCRIPT = 10021
      
      
      # The Plugin Class
      class TestTrans(plugins.TagData):
      
          def __init__(self):       
      
              self.data = None
      
          def Init(self, node):
      
              self.InitAttr(node, c4d.BaseList2D, PY_MORPH_LINK)
              # node[PY_MORPH_LINK] = None
      
              self.InitAttr(node, str, PY_TRANSCRIPT_LINK)
              # node[PY_TRANSCRIPT_LINK] = ""
      
              self.InitAttr(node, c4d.BaseTime, PY_SYNC_START)
              node[PY_SYNC_START] = c4d.BaseTime()
      
              return True
          
          def load_transcript(self, op):
      
              if op[PY_TRANSCRIPT_LINK] != "":
                  with open(op[PY_TRANSCRIPT_LINK], "r") as transfile:
                      self.data = json.load(transfile)
      
          def move2(self, tag, frame, value):
              print("2. Hello in function")
      
          def Execute(self, tag, doc, op, bt, priority, flags):
      
              if self.data:
      
                  pose_morph = tag[PY_MORPH_LINK]
      
                  if not pose_morph:
                      return c4d.EXECUTIONRESULT_OK
      
                  morph_count = pose_morph.GetMorphCount()
                  print(pose_morph)
                  print(self.data["words"])
      
                  frame = doc.GetTime().GetFrame(doc.GetFps()) - tag[PY_SYNC_START]  #Here it is crashing
                  print(frame)
      
                  if frame == 10:
                      print("1. Hello")
      
                  self.move2(tag, frame, 1)
      
              return c4d.EXECUTIONRESULT_OK
         
      
          def Message(self, node, type, data):
      
              if type == c4d.MSG_DESCRIPTION_COMMAND:
      
                  if data["id"][0].id == PY_LOAD_TRANSCRIPT:
                      self.load_transcript(node)
      
              if type == c4d.MSG_DESCRIPTION_POSTSETPARAMETER:
                  if data["descid"][0].id == PY_TRANSCRIPT_LINK:
                      print("POSTSETPARAMETER")
                      self.load_transcript(node)
      
              return True
      
      
      # main
      if __name__ == "__main__":
          # load icon.tif from res into bmp
          bmp = bitmaps.BaseBitmap()
          dir, file = os.path.split(__file__)
          fn = os.path.join(dir, "res", "icon.tif")
          bmp.InitWith(fn)
      
          new_bmp = c4d.bitmaps.InitResourceBitmap(1051133)
      
          # register the plugin
          c4d.plugins.RegisterTagPlugin(id=PLUGIN_ID,
                                        str="Test-Trans",
                                        info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE,
                                        description="testtrans",
                                        g=TestTrans, icon=bmp)
      
      

      res-file:

      CONTAINER Testtrans
      {
      	NAME TESTTRANS;
      	INCLUDE Texpression;
      
      	GROUP ID_TAGPROPERTIES
      	{
              LINK PY_MORPH_LINK
              {
                  ACCEPT { Tbase; }
              }
      
              FILENAME PY_TRANSCRIPT_LINK
              {
                ANIM ON;
              }
      
              BASETIME PY_SYNC_START {}
      
      
      	}
      }
      

      header-file:

      #ifndef _TESTTRANS_H_
      #define _TESTTRANS_H_
      enum
      {
          PY_MORPH_LINK           = 10000,
          PY_TRANSCRIPT_LINK      = 10001,
          PY_SYNC_START           = 10018,
      
      	//GV_XPEMIT_NODE_DUMMY
      };
      #endif // ${FILE_NAME}
      

      string-file:

      STRINGTABLE Testtrans // derselbe Name wie res-file
      {
      	TESTTRANS                       "Test-Trans";
      	PY_MORPH_LINK                 "Pose-Morph-Tag";
      	PY_TRANSCRIPT_LINK            "Transcript";
             PY_SYNC_START                 "Start";
      
      }
      

      Best Regards
      Tom

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

        Hey @ThomasB,

        Thank you for reaching out to us. Thank you for your very clear posting, but your three questions should have been at least two or better three topics because they are all entirely different subjects. I did not fork your topic in this case because you did put so much work into your posting, but I would want to give you a gentle reminder that topics should only contain a singular topic.

        About Your Questions

        Crash in TagData.Execute

        No, this has nothing to do with threading and your code is (mostly) correct. There is a bug in 2023 in BaseTime.__sub__, it has already been fixed in the API of the upcoming release.

        Note that we support BaseTime.__sub__ with other being an int; this has been added in 2023 and is the cause of the bug. But we do not support __rsub__. I.e., BaseTime - int (__sub__) is supported but int - BaseTime (__rsub__) is not. The int support has also not yet been documented.

        When you call frame = doc.GetTime().GetFrame(doc.GetFps()) - tag[PY_SYNC_START] you invoke __rsub__ which then defaults to __sub__ and triggers the bug. When subtracting an int from a BaseTime, the int is also interpreted as a value in seconds and not as frame value, because a BaseTime has no inherent fps.

        >> import c4d
        >> bt: c4d.BaseTime = c4d.BaseTime(50, 25)
        >> bt.Get()
        2.0
        >> # 1 will be subtracted from the value in seconds which represented by #bt.
        >> (bt - 1).Get()
        1.0
        

        So, you probably meant here:

        fps: int = doc.GetFps()
        frame: int = doc.GetTime().GetFrame(fps) - tag[PY_SYNC_START].GetFrame(fps)
        

        Does not Invoke load_transcript

        Well, when your statement print("POSTSETPARAMETER") is being hit, so will be the line after it. The interpreter will not magically not call something. Please also do understand that we cannot debug your code for you.

        What can happen here is that it looks like that load_transcript is not running because:

        1. Your condition op[PY_TRANSCRIPT_LINK] != "" is not being met.
        2. Whatever relies on self.data only later reacts to it being updated or never reacts at all.
        3. You get on NodeData.Message calls that are not on the main thread. All file operations are not thread-safe, you cannot have two things accessing one file at the same time. You should wrap all file operations in a c4d.threading.GeIsMainThread condition.

        In the end, you probably have to do a bit more debugging here.

        That MSG_DESCRIPTION_POSTSETPARAMETER is not broadcasted for parameter changes of a node that is linked is normal, because you listen here to the messages of your node and not the messages of the linked node.

        Tposemorph Symbol

        Yes, you are right, the symbol is not exposed in resources, that is an oversight or bug if you will. You must use the numeric value of Tposemorph instead:

        LINK PY_MORPH_LINK
        {
          ANIM OFF;
          ACCEPT { 1024237; } // Value for Tposemorph
        }
        

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

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

          @ferdinand

          Thank you Ferdinand for your leniency regarding the three questions..
          Will take note of that in the future.

          =====BaseTime=====
          Which just surprises me about the BaseTime problem is, that it worked in the Python tag. I didn't get an error message and the prototype worked very well.
          So I also tried instead of BaseTime int type value in the plugin, but it crashed. It confused me a bit. So I try your suggestion.

          # In the python tag it worked with int
          
          # starf_frame was an int
           frame = doc.GetTime().GetFrame(doc.GetFps()) - op[c4d.ID_USERDATA,start_frame]
          

          ====PoseMorph Symbol====
          Regarding the posmorph ID, I should have figured that out myself

          Thanks for your quick respond

          Tom

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

            This post is deleted!
            1 Reply Last reply Reply Quote 0
            • First post
              Last post