Hello @Jonas-Mortensen,
Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our Forum and Support Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:
About your First Question
I think there are some misconceptions going one regarding to what tags do in Cinema 4D and why your code does what it does. We also had some troubles understanding your goals.
I am aware parameter linking can be done manually, but GetDataInstance applies it to all parameters instead of you choosing individualy.
That is not quite true, depending on how literal one is with the word "linking". You cannot establish a binding between two parameters in the API without implmenting that yourself, i.e., there is no API function for that.
I could speculate here more about your intentions, but I leave it to my code example to line out some details.
Cheers,
Ferdinand
PS: Please do not use semicolons as statement delimters in Python - it makes my skin crawl :D
Updated file: parameterlinking.c4d
Code:
"""Demonsstrates at three examples how and when expressions, i.e., tags are executed.
"""
import c4d
op: c4d.BaseTag # The Python tag holding this code.
def main():
# When you define these values outside of #main, i.e., in the module scope, they will not
# update when the user changes the link or moves the tag.
link: c4d.BaseList2D | None = op[c4d.ID_USERDATA, 1] # Our BaseLink
host: c4d.BaseObject = op.GetMain() # And the object hosting the tag.
mode: int = op[c4d.ID_USERDATA, 2] # User data to select between the three example sections.
if mode == 0:
# BaseLink fields can contain other things than objects. We should also avoid copying
# data from one object sub-type to another, e.g., from Ocube to Osplinecircle for example.
if not isinstance(link, c4d.BaseObject) or link.GetType() != host.GetType():
return
# The implicit question of your is "why does this work?". And the answer is different than
# what you might think. Calling BaseList2D.SetData will copy data from the input container,
# so calling BaseList2D.GetDataInstance over BaseList2D.GetData is irrelevant.
host.SetData(link.GetDataInstance())
return
if mode == 1:
# More over, using a BaseLink is irrelevant here too. We could change the code to this, and
# it would still work. So, this does not work because you linked #link in the ui of #op. We
# can demonstrate this by just blindly picking the first object in the document.
link: c4d.BaseObject | None = op.GetDocument().GetMain()
if not isinstance(link, c4d.BaseObject) or link.GetType() != host.GetType():
return
host.SetData(link.GetData())
return
if mode == 2:
# There reason is that when you manipulate the parameters of the node #link, you will cause
# the passes to be executed on the document, which means that caches are rebuilt, as for
# example the geometry cache of #link to reflect its new parameter state, but also the
# expression pass, i.e., all tags in the scene. Which will trigger then this code here. But
# there are user actions which do not invoke the passess being invoked on a document.
# We can demonstrate this by copying over the transform of #link to #host instead of its
# data container. Manipulatiiong the transform of an object will not cause the scene to be
# reevaluated, which is why we will see no change on #host when we transform #link
if not isinstance(link, c4d.BaseObject):
return
host.SetMg(link.GetMg())
# Expressions, a.k.a., tags, are a dedicated state in the state machine that is Cinema 4D's
# scene execution. For details see https://tinyurl.com/4r7v6wta .
#
# Neither can "parameter linking [...] be done manually" as you have put it, nor does an
# expression link evvents of two entities. Expressions are executed when the expression pass
# is called on a document. There are some exceptions:
#
# * Messages sent to objects are sometimes propagated to their hosted tags.
# * Appart from pass execution, tags are also excuted on events being added, e.g., the user
# changing the object selection in the object manager.
# * The Python Programming tag has the dedicated parameter "Frame Dependent" in its "Basic"
# tab to force tag execution on each frame on playback.