<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Python tag initalization?]]></title><description><![CDATA[<p dir="auto">Hello everyone,</p>
<p dir="auto">I'm new here <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /></p>
<p dir="auto">I've a python script that creates a Python tag and injects some code into it. This Python tag is then searching in the hierarchy for objects to link to. This search is in the main() so I guess it executing every frame/interaction, which doesn't sound very performant, especially as it will relink the same object over and over again.</p>
<p dir="auto">Is there a way to initialize the python tag somehow, so in the example below, crtl_01 gets assigned just a single time, and then keeps its value without updating it?</p>
<p dir="auto">Is initialization the correct term for this?</p>
<p dir="auto">The code looks similar to this:</p>
<pre><code>import c4d

def get_object_from_python_tag(tag):
    if tag and tag.GetType() == c4d.Tpython:
        linked_object = tag.GetMain()
        if linked_object:
            return linked_object
    return None

def get_parent_object(obj):
    return obj.GetUp()

def find_object_in_hierarchy_by_name(current_obj, target_name):
    if current_obj.GetName() == target_name:
        return current_obj

    child = current_obj.GetDown()
    while child:
        result = find_object_in_hierarchy_by_name(child, target_name)
        if result:
            return result
        child = child.GetNext()

    return None

def main():
    python_null = get_object_from_python_tag(op)

    ctrl_01 = find_object_in_hierarchy_by_name(get_parent_object(python_null), "Helper_01")

# Execution
if __name__ == '__main__':
    main()
</code></pre>
]]></description><link>http://developers.maxon.net/forum/topic/15294/python-tag-initalization</link><generator>RSS for Node</generator><lastBuildDate>Fri, 07 Aug 2026 10:42:52 GMT</lastBuildDate><atom:link href="http://developers.maxon.net/forum/topic/15294.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 19 Dec 2023 17:21:42 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Python tag initalization? on Thu, 21 Dec 2023 09:23:08 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/m_adam">@<bdi>m_adam</bdi></a></p>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/m_adam">@<bdi>m_adam</bdi></a> said in <a href="https://developers.maxon.net/forum/post/73396" target="_blank" rel="noopener noreferrer nofollow ugc">Python tag initalization?</a>:</p>
<blockquote>
<p dir="auto">OM is not single threaded,</p>
</blockquote>
<p dir="auto">Oh, that's an interesting insight for me. Perhaps I was misinformed, as Character Rigs had the tendency to get slow quite easily in C4D, and Animators look envy over to Maya, as they do have a parallel evaluation (and caching). Though I'm aware that there are changes/improvements to C4D performance lately. Thanks for the link. A lot of new information to learn an absorb <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /></p>
]]></description><link>http://developers.maxon.net/forum/post/73397</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73397</guid><dc:creator><![CDATA[gaschka]]></dc:creator><pubDate>Thu, 21 Dec 2023 09:23:08 GMT</pubDate></item><item><title><![CDATA[Reply to Python tag initalization? on Thu, 21 Dec 2023 09:15:35 GMT]]></title><description><![CDATA[<p dir="auto">OM is not single threaded, see <a href="https://developers.maxon.net/docs/py/2024_0_0a/manuals/manual_threading.html" target="_blank" rel="noopener noreferrer nofollow ugc">Threading Manual</a> all operations of a scene execution are not done in the same thread / main thread. The main bottleneck will be the execution of Python by itself. A Xpresso setup may be faster but is single threaded and I don't think will let you do the same thing.</p>
<p dir="auto">With that's said if you know that the object will change a lot and you will need to perform the search over and over then yes you may rethink your approach and probably use a link field, so the user can rewire the object instead of you searching for it but what you are doing currently is fine.</p>
]]></description><link>http://developers.maxon.net/forum/post/73396</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73396</guid><dc:creator><![CDATA[m_adam]]></dc:creator><pubDate>Thu, 21 Dec 2023 09:15:35 GMT</pubDate></item><item><title><![CDATA[Reply to Python tag initalization? on Thu, 21 Dec 2023 09:14:57 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/baca">@<bdi>baca</bdi></a> thanks for the insights! I guess I sit too long next to game devs who have a tendency for premature optimizations and got infected <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f602.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--joy" style="height:23px;width:auto;vertical-align:middle" title="😂" alt="😂" /><br />
But I can second that: I know so many C4D artists who don't have a clue, neither they care, about how to keep theirs scene performant.</p>
]]></description><link>http://developers.maxon.net/forum/post/73395</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73395</guid><dc:creator><![CDATA[gaschka]]></dc:creator><pubDate>Thu, 21 Dec 2023 09:14:57 GMT</pubDate></item><item><title><![CDATA[Reply to Python tag initalization? on Thu, 21 Dec 2023 09:07:31 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/gaschka">@<bdi>gaschka</bdi></a><br />
I can think like hundreds of operations are nothing for the Python<br />
When it counts as thousands — you'll notice that.</p>
<p dir="auto">Optimizations requires some knowledge of Cinema tech side, to listen events, understand execution context, and so on.<br />
Because there might be multiple scenarios, which you're not expecting in your "optimal" logic.<br />
Main issue is the user — who will delete your key tags/objects, move objects within hierarchy, wrap objects into a null, and so on</p>
]]></description><link>http://developers.maxon.net/forum/post/73394</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73394</guid><dc:creator><![CDATA[baca]]></dc:creator><pubDate>Thu, 21 Dec 2023 09:07:31 GMT</pubDate></item><item><title><![CDATA[Reply to Python tag initalization? on Thu, 21 Dec 2023 08:53:54 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/m_adam">@<bdi>m_adam</bdi></a> thanks a lot for the explaination and the code. Messages is a new concept for me and something I'll definitely explore.</p>
<p dir="auto">Referring to point 1: So checking if the object is changed, even with the OM traversal, is something I can ignore performance wise? I'm asking, because I want the tag to control a custom piece of a character rig, perhaps with multiple copies of it. Rigs tend to be quite performance critical and running single threaded in C4D due to the OM so I wonder if this kind of search in the OM can have a significant impact?</p>
]]></description><link>http://developers.maxon.net/forum/post/73391</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73391</guid><dc:creator><![CDATA[gaschka]]></dc:creator><pubDate>Thu, 21 Dec 2023 08:53:54 GMT</pubDate></item><item><title><![CDATA[Reply to Python tag initalization? on Wed, 20 Dec 2023 09:35:54 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/gaschka">@<bdi>gaschka</bdi></a>, there is multiple way to set it up.</p>
<ol>
<li>Do as you do currently, in each execution, check if the object are the same if not update it. I would say there is nothing really wrong about it.</li>
<li>If you want the user to have the ability to change it, just create a link user data.<br />
Then either your tag or the script that create the tag, have the duty to define it and within your execute method you do as you do currently and check if the link from the user data should be updated or not.</li>
<li>The name is hardcoded, you can react to the <a href="https://developers.maxon.net/docs/py/2024_0_0a/consts/MSG_C4DATOM_PLUGINS.html?highlight=msg_menuprepare#c4d.MSG_MENUPREPARE" target="_blank" rel="noopener noreferrer nofollow ugc">MSG_MENUPREPARE</a> in the <a href="https://developers.maxon.net/docs/py/2024_0_0a/manuals/manual_py_programming_tag.html" target="_blank" rel="noopener noreferrer nofollow ugc">message function of a tag</a> like so:</li>
</ol>
<pre><code>import c4d

CTRL_NAME = "Helper_01"

def find_object_in_hierarchy_by_name(current_obj, target_name):
    if current_obj.GetName() == target_name:
        return current_obj

    child = current_obj.GetDown()
    while child:
        result = find_object_in_hierarchy_by_name(child, target_name)
        if result:
            return result
        child = child.GetNext()

    return None

def cache_ctrl_01(target_name):
    python_null = op.GetObject()
    ctrl_01 = find_object_in_hierarchy_by_name(python_null.GetUp(), target_name)
    op[10001] = ctrl_01

def message(id, data):
    if id == c4d.MSG_MENUPREPARE:
        cache_ctrl_01(CTRL_NAME)

def main():
    ctrl_01 = op[10001]
    # Check if the object exist and is not deleted retrieve it
    if ctrl_01 is None or not ctrl_01.IsAlive():
        cache_ctrl_01(CTRL_NAME)
        ctrl_01 = op[10001]

        # If its still None, then something is wrong raise an error in the Python Console
        if ctrl_01 is None or not ctrl_01.IsAlive():
            raise ValueError(f"Unable to find {CTRL_NAME}")

    print(op[10001])
</code></pre>
<p dir="auto"><code>op[10001]</code> will write into the basecontainer of op (the tag). A BaseContainer is like a dict in python, except that it's native to Cinema 4D and used all over the place in Cinema 4D. For example the parameter of an object,tags,material,document are stored in a BaseContainer. When you pass some settings to execute a command, you pass a BaseContainer with the appropriate value in it. I've used the id 10001 as any ID above 10000 are safe to use and will not conflict with internal stuff, but if you really want to be safe, you should register a plugin id in <a href="https://plugincafe.maxon.net/" target="_blank" rel="noopener noreferrer nofollow ugc">plugincafe</a> we did not yet migrated pluginId to this new website so you will need an old account, the migration will happen in the upcoming weeks/months.</p>
<p dir="auto">Then the code to create your tag should be:</p>
<pre><code>import c4d

SOME_PYTHON_TAG_CODE = """import c4d

CTRL_NAME = "Helper_01"

def find_object_in_hierarchy_by_name(current_obj, target_name):
    if current_obj.GetName() == target_name:
        return current_obj

    child = current_obj.GetDown()
    while child:
        result = find_object_in_hierarchy_by_name(child, target_name)
        if result:
            return result
        child = child.GetNext()

    return None

def cache_ctrl_01(target_name):
    python_null = op.GetObject()
    ctrl_01 = find_object_in_hierarchy_by_name(python_null.GetUp(), target_name)
    op[10001] = ctrl_01

def message(id, data):
    if id == c4d.MSG_MENUPREPARE:
        cache_ctrl_01(CTRL_NAME)

def main():
    ctrl_01 = op[10001]
    # Check if the object exist and is not deleted retrieve it
    if ctrl_01 is None or not ctrl_01.IsAlive():
        cache_ctrl_01(CTRL_NAME)
        ctrl_01 = op[10001]

        # If its still None, then something is wrong raise an error in the Python Console
        if ctrl_01 is None or not ctrl_01.IsAlive():
            raise ValueError(f"Unable to find {CTRL_NAME}")

    print(op[10001])
"""

def add_python_tag(obj):
    if not isinstance(obj, c4d.BaseObject):
        return None

    python_tag = obj.MakeTag(c4d.Tpython)
    doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, python_tag)
    python_tag[c4d.TPYTHON_CODE] = SOME_PYTHON_TAG_CODE
    python_tag.Message(c4d.MSG_MENUPREPARE)

    return python_tag

# Execution
if __name__ == '__main__':
    doc.StartUndo()
    add_python_tag(op)
    doc.EndUndo()
    c4d.EventAdd()
</code></pre>
<p dir="auto">Cheers,<br />
Maxime.</p>
]]></description><link>http://developers.maxon.net/forum/post/73383</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/73383</guid><dc:creator><![CDATA[m_adam]]></dc:creator><pubDate>Wed, 20 Dec 2023 09:35:54 GMT</pubDate></item></channel></rss>