Crash when apply a Tag plugin.
-
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 searchCheers~
-
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 -
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 thingsAnd 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 -
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,
Sebastianimport 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)
-
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 -
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.
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 lickOK
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 namedPYCIRCLEOBJECT_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. AndOsplineprimitive
loaded in the parameters which are shared by all spline primitives, as for example Plane, Reverse, etc.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; } } }
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 ofTbase
.Texpression
extendsTbase
and whileTbase
is used for generic tags which usually do not modify the scene, e.g., the "Display" tagTdisplay
is based onTbase
: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" tagTlookatcamera
: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.
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:Cheers,
Ferdinand -
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 -