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

    Crash when apply a Tag plugin.

    Cinema 4D SDK
    2023 python windows
    3
    7
    957
    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.
    • DunhouD
      Dunhou
      last edited by

      Hello everyone,

      I am working on a tag plugin with cloner, I get a copy of teh Github py-look at camera.pyp example and start my first step with a tag plugin, the basic goal is stiky a link object to a index of a cloner object and also can be offset.

      But I modifiy the example and test it, cinema always crash when apply the tag to an object. even I just return exe_ok ,
      I don't know what is happend.

      I already read some topic:

      • https://developers.maxon.net/forum/topic/13678/help-needed-res-files-dialogs-etc-plugin-beginner
      • https://developers.maxon.net/forum/topic/13144/python-tag-plugin-doesn-t-work-properly-with-resource-files
      • https://developers.maxon.net/forum/topic/14315/solved-how-to-setup-a-ctrack-on-tag-plugin-ui-slider-with-extended-details

      Here is the little file of the plugin.tag test.zip

      By the way, is there another way to create UI in python? the res solution is herrible to use and no document to search๐Ÿ˜ข

      Cheers~

      https://boghma.com
      https://github.com/DunHouGo

      1 Reply Last reply Reply Quote 0
      • H
        HerrMay
        last edited by

        Hello @Dunhou,

        I checked the code you provided. There was a wrong line in your res file.

         INCLUDE Taligncloner; 
        

        has to be:

         INCLUDE Texpression;
        
        // The description defintion of the tag Taligncloner.
        CONTAINER Taligncloner
        {
            NAME Taligncloner;
            INCLUDE Texpression;
        
            // The main "Tag" tab of the tag.
            GROUP ID_TAGPROPERTIES
            {
                LINK LINK_NODE { FIT_H; ACCEPT { Obase; } }
                REAL CLONER_INDEX  { UNIT METER; STEP 1; }
                BOOL STIKY_ON_CLONER { }
            }
        }
        

        Besides the fact that the object which is supposed to stick to the cloner jumps around each refresh, it now works for me in S26. ๐Ÿ˜‰

        But you are right, creation and editing of the res file is a royal pain in the a**. ๐Ÿ˜„

        Hope this helped.

        Cheers,
        Sebastian

        DunhouD 1 Reply Last reply Reply Quote 0
        • DunhouD
          Dunhou @HerrMay
          last edited by

          Hey @HerrMay ,Thanks for that!

          What is the INCLUDE Texpression; means? Could you explain a little deeper, I did't find a document for those things๐Ÿ˜ง

          And honestly, The .res file code style is no document, I had to search in the resoure folder and copy and guess how it works,
          such painful...

          And yes , jumps around each refresh has it is also a problem , I test on a python tag first, it also happened, This my first time to a node plugin but not a command plugin , it is an adventure๐Ÿ˜ต

          Cheers~
          DunHou

          https://boghma.com
          https://github.com/DunHouGo

          1 Reply Last reply Reply Quote 0
          • H
            HerrMay
            last edited by

            Hello @Dunhou,

            I'm not super sure about what INCLUDE Texpression means in regards to c4ds deeper resource implementation. I guess it's just the way to say how your tag plugin should be treated. That it should be calculated as an expression in c4ds execution pipeline, if that makes sense.
            Maybe someone from the sdk team can jump in here and provide a little more elaborate answer. ๐Ÿ˜„

            By the way, a nice idea for a tag plugin. ๐Ÿ˜‰
            I took the freedom to investigate the sticking respectively the refreshing issue that is. And I made the index parameter loop as well. ๐Ÿ˜‰

            Find below a commented version of your code that works like a charm for me.

            Cheers,
            Sebastian

            import os
            import c4d
            from c4d.modules import mograph as mo
            
            # Be sure to use a unique ID obtained from www.plugincafe.com
            PLUGIN_ID = 1060757
            
            
            class LookAtCamera(c4d.plugins.TagData):
                """Look at Camera"""
                
                def Init(self, node: c4d.GeListNode):
                    """Called when Cinema 4D Initialize the TagData (used to define, default values).
            
                    Args:
                        node (c4d.GeListNode): The instance of the TagData.
            
                    Returns:
                        True on success, otherwise False.
                    """
                    self.InitAttr(node, int, c4d.CLONER_INDEX)
                    self.InitAttr(node, c4d.BaseObject, c4d.LINK_NODE)
                    self.InitAttr(node, bool, c4d.STIKY_ON_CLONER)
                    
                    node[c4d.CLONER_INDEX] = 0
                    node[c4d.LINK_NODE] = None
                    node[c4d.STIKY_ON_CLONER] = False
            
                    return True
                
                def Execute(self, tag, doc, op, bt, priority, flags):
                    """Called by Cinema 4D at each Scene Execution, this is the place where calculation should take place.
            
                    Args:
                        tag (c4d.BaseTag): The instance of the TagData.
                        doc (c4d.documents.BaseDocument): The host document of the tag's object.
                        op (c4d.BaseObject): The host object of the tag.
                        bt (c4d.threading.BaseThread): The Thread that execute the this TagData.
                        priority (EXECUTIONPRIORITY): Information about the execution priority of this TagData.
                        flags (EXECUTIONFLAGS): Information about when this TagData is executed.
                    """
            
                    stick = tag[c4d.STIKY_ON_CLONER] # Should the linked node stick?
                    link_node = tag[c4d.LINK_NODE] # The linked node
            
                    # If there is no linked node or stick is not enabled there is no need for computation. Return early.
                    if not link_node or not stick:
                        return c4d.EXECUTIONRESULT_OK
            
                    # Check whether op is a cloner object
                    if not op.CheckType(1018544): # I like to use op.CheckType here over op.GetType() because it directly returns a boolean value I can compare with.
                        return c4d.EXECUTIONRESULT_OK
                    
                    # Get MoData
                    md = mo.GeGetMoData(op)
                    if not md:
                        return c4d.EXECUTIONRESULT_OK
                    
                    user_index = tag[c4d.CLONER_INDEX] # The index chosen by the user
                    count = md.GetCount() # Get the clone count of our cloner
                    marr = md.GetArray(c4d.MODATA_MATRIX) # Get the MoData array which holds the matrices of each clone
                    index = user_index % count # Make the index loop so that you get back to e.g. index 0 if index is e.g. greater than your clone count. 
            
                    cloner_mg = op.GetMg() # Get the global matrix of the cloner
                    clone_mg = marr[index] # Get the matrix of the clone we want to stick our linked node to
                    link_node.SetMg(cloner_mg*clone_mg) # Multiply both matrices and set the global matrix of the linked node to the matrix of the clone we get over our index
                    link_node.Message(c4d.MSG_UPDATE) # Inform the linked node that it should update its matrix
            
                    return c4d.EXECUTIONRESULT_OK
            
            if __name__ == "__main__":
                # Retrieves the icon path
                directory, _ = os.path.split(__file__)
                fn = os.path.join(directory, "res", "icon.png")
            
                # Creates a BaseBitmap
                bmp = c4d.bitmaps.BaseBitmap()
                if bmp is None:
                    raise MemoryError("Failed to create a BaseBitmap.")
            
                # Init the BaseBitmap with the icon
                if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK:
                    raise MemoryError("Failed to initialize the BaseBitmap.")
            
                c4d.plugins.RegisterTagPlugin(id=PLUGIN_ID,
                                              str="Taligncloner",
                                              info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE,
                                              g=LookAtCamera,
                                              description="Taligncloner",
                                              icon=bmp)
            
            
            DunhouD ferdinandF 2 Replies Last reply Reply Quote 0
            • DunhouD
              Dunhou @HerrMay
              last edited by

              Ohhh thanks dude, @HerrMay Great work for the fix, I have a test on script manager, but the plugin loading failed, anyway , thanks for your help, it real works.

              yes, actually need a document or something with the gui with res file. but I think it is way loooooong in the todo list๐Ÿ˜ง

              Cheers~
              DunHou

              https://boghma.com
              https://github.com/DunHouGo

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

                Hello @Dunhou,

                Thank you for reaching out to us and thank you at @HerrMay for providing what I would think is the correct answer.

                At least on my machine, nothing is crashing here, it is just that the description of the tag is malformed on line five.

                6ff23335-b6c4-4d15-9ef4-47f3a84ca4b2-image.png

                In this case, it is such a severe error, that Cinema 4D fails to load the description at all because it is cyclically referencing itself. The keyword INCLUDE in a resource allows us to include another resource in that resource. And when we try to reference the resource, we are defining, Cinema 4D is understandably confused. For less severe descriptions errors, one usually is able to then lick OK a few times to get Cinema 4D to load what it does understand. But that does not work here, and one is caught in an endless loop of self-reference.

                In practice, INCLUDE is usually used to load in the base description of something. So, when we take the simple description of the opydoublecircle example plugin which only defines one parameter named PYCIRCLEOBJECT_RAD,

                CONTAINER Opydoublecircle
                {
                	NAME Opydoublecircle;
                	INCLUDE Obase; // Loads 
                
                	GROUP ID_OBJECTPROPERTIES
                	{
                		REAL PYCIRCLEOBJECT_RAD { UNIT METER; MIN 0.0; }
                	}
                	INCLUDE Osplineprimitive;
                }
                

                we can see that Obase loaded the Basic and Coordinates tabs into that object description that every object must have. And Osplineprimitive loaded in the parameters which are shared by all spline primitives, as for example Plane, Reverse, etc.

                c2a597a9-df44-439e-aa0c-62908933dbeb-image.png

                When we remove Osplineprimitive, all these parameters will not be added to our object.

                CONTAINER Opydoublecircle
                {
                	NAME Opydoublecircle;
                	INCLUDE Obase; // Loads 
                
                	GROUP ID_OBJECTPROPERTIES
                	{
                		REAL PYCIRCLEOBJECT_RAD { UNIT METER; MIN 0.0; }
                	}
                }
                

                7a26bad0-db17-4ad5-ba7e-0de7490bc743-image.png

                What slightly complicates this, is that (allmost) all NodeData derived plugin types must include at least their base description, e.g., Obase for objects, Tbase for tags, Mbase for materials, Xbase for shaders, and so on.

                In some cases speccializations are allowed, as for example including Texpression instead of Tbase. Texpression extends Tbase and while Tbase is used for generic tags which usually do not modify the scene, e.g., the "Display" tag Tdisplay is based on Tbase:

                CONTAINER Tdisplay
                {
                	NAME Tdisplay;
                	INCLUDE Tbase;
                
                	GROUP ID_TAGPROPERTIES
                	{
                		COLUMNS 2;
                		BOOL DISPLAYTAG_AFFECT_DISPLAYMODE { }
                		LONG DISPLAYTAG_SDISPLAYMODE
                		{
                

                Texpression is usually used by tags which do modify a scene in some shape or form, e.g, the "Look at Camera" tag Tlookatcamera:

                CONTAINER Tlookatcamera
                {
                	NAME Tlookatcamera;
                	INCLUDE Texpression;
                
                	GROUP ID_TAGPROPERTIES
                	{
                		BOOL LOOKATCAMERA_PITCH { }
                	}
                }
                

                The difference is then simply that such tags whill have the expression paramaters in their 'Basic' tab.

                a91e446d-4b0d-4fcc-a0a4-72179491d19c-image.png

                As said before, I already have updating the GUI manuals on my desk, it will be one of the next things I do, as they are factually non-existent for Python and a bit outdated and assumptious regarding what users will easily understand for C++. But I would still recommend Python users having a look at the C++ docs, as the information provided there is directly transferable to Python.

                • Resource File Manual: Provides an overview over the different resource types.
                • Description Resources Manual: Provides an overview of the form of resource files you are writing here.

                As lined out in other threads, greping the Cinema 4D resource folder, e.g., C:\Program Files\Maxon\2023.1.3\resource\ is a good way to gather knowledge on your own right now. I like using Agent Ransack for doing things like this, but any grep-like tool, including these built into text editors, will do:

                afde649f-398b-439c-b596-12ffc6b12967-image.png

                Cheers,
                Ferdinand

                MAXON SDK Specialist
                developers.maxon.net

                DunhouD 1 Reply Last reply Reply Quote 1
                • DunhouD
                  Dunhou @ferdinand
                  last edited by

                  Hey @ferdinand ,Thanks for your detailed explains forever.

                  Now it is clear to read the res files , and you show me the Agent Ransack last year, I use this software for learn something , and the C++ document is also good for the res file, but some of the data is distribute anywhere , like BITMAPMUTTON , I remember that I search for no fading option for a long time, but in python document it has a user friendly position in sdk.

                  Maybe a document improvement or more Github examples are both welcomed( seems lots of works๐Ÿ˜ฒ )

                  Thanks for your patience๏ผ

                  Cheers~
                  DunHou

                  https://boghma.com
                  https://github.com/DunHouGo

                  1 Reply Last reply Reply Quote 0
                  • DunhouD Dunhou referenced this topic on
                  • First post
                    Last post