• How to select directories in a CUSTOMGUI_FILENAME?

    s26 python
    3
    0 Votes
    3 Posts
    723 Views
    P
    Hi @ferdinand , Thanks a lot, that's exactly what I was looking for ! flags: c4d.BaseContainer = c4d.BaseContainer() flags[c4d.FILENAME_DIRECTORY] = True # Add a CUSTOMGUI_FILENAME with our flags settings. self.AddCustomGui(id=MyDialog.ID_FILENAME, pluginid=c4d.CUSTOMGUI_FILENAME, name="Path", flags=c4d.BFH_SCALEFIT, minw=0, minh=0, customdata=flags)
  • Plug-in running fine on one OS but not another

    windows sdk
    13
    1
    0 Votes
    13 Posts
    2k Views
    Y
    @ferdinand Yes. it's solved. Thank you.
  • ActiveObjectManager_SetObject to display BaseObject in a GetListHead

    c++ sdk
    2
    0 Votes
    2 Posts
    426 Views
    ferdinandF
    Hello @kbar, Thank you for reaching out to us. This is a tricky one to answer, and my first instinct was that this is not too surprising due to what you do with your GeListHead, but the devil lies in the detail. In general, I would say that the safest route would be the one many of our implementations take: Displaying elements that are not part of the "standardized" branches of a scene graph via a DescriptionCustomGui wrapped by a custom GUI of yours which is part of a description of a (set of) node type(s) you provide. The FieldList data type/GUI does this for example. Overview Simply adding a custom branch in form of a GeListHead to a node of your choice will not make this custom branch discoverable via BranchInfo. This is because there is hard-coded data in the Cinema 4D core for this branch discovery. You can of course manually traverse the branches of your node. In the Attribute Manager SetObject implementation, this hardcoded branch structure is not being checked directly as far as I can see, but the Attribute Manger modes rely implicitly on it. You can register new Attribute Manger modes with ActiveObjectManager_RegisterMode which binds than that mode to a hook as for example shown in [1] (for materials in this case), see the MESSAGEHOOK documentation for details. It shows the case for tags as used internally. The object mode case is much more complex, but it will effectively fail on AOM_MSG_GETATOMLIST in your scene setup because the traversal done there assumes objects to appear in "object " branches only - which is not true in your case. Solutions I personally would still consider the DescriptionCustomGui route the safest way, especially because the GUI has the DESCRIPTION_OBJECTSNOTINDOC flag which allows you to also display orphaned nodes. Implement your custom attribute manager mode, which can deal with your custom scene traversal structure and mark your nodes with NBIT_ACTIVE so that the hook can find them. Regarding Xpresso nodes: They have their own branches which are respected in the AM implementation. As a warning: There are also quite a few hacks in the AM for Nodes API and shader nodes, especially regarding the traversal. In general, I would consider this non-regular scene structure of yours a problem with the AM because of how often Cinema 4D internally relies on a specific makeup of branches. It could very well be that you implement your AM mode, and everything will then work fine, but I cannot guarantee that. Which is a further point why I personally would gravitate towards the first solution. Cheers, Ferdinand [1]: static GeData MaterialMessageHook(const BaseContainer &msg, void *data) { switch (msg.GetId()) { case AOM_MSG_ISENABLED: return true; case AOM_MSG_GETATOMLIST: { BaseDocument *doc = GetActiveDocument(); if (!doc) break; doc->GetActiveMaterials(*((AtomArray*)data)); return true; } break; } return false; }
  • Can i get global input event ?

    python s26
    3
    0 Votes
    3 Posts
    400 Views
    gheyretG
    @ferdinand Wow~ Thank you so much bro
  • Get Node By Name?

    r25 python
    3
    0 Votes
    3 Posts
    356 Views
    B
    @Manuel Ah gotcha. It's only available R26 onwards. That's why I can't see something related in my R25 documentation.
  • Get asset from asset browser python

    python
    5
    0 Votes
    5 Posts
    1k Views
    K
    @ferdinand Thanks a lot Ferdinand for this detailed and complete answer! This is exactly what I hoped to do! I tested the code and it works great! Since a few of the fixes you use are not recommended, i will solve it in another way for now, until it gets fixed for python, or i switch to C++. I got my plugin doing what i want, for the moment. Pretty sure this will also help someone else in the future. Have a nice day!
  • Iterate through all Inputs and Outputs of a Given Node?

    r25 python
    5
    0 Votes
    5 Posts
    564 Views
    B
    @manuel ah gotcha. the node kinda. thanks. will close this thread for now.
  • Project Tool Stops At Non-Existent Path

    project tool sdk
    4
    1
    0 Votes
    4 Posts
    987 Views
    M
    Hi @Yakuza just in case you do have space in your Cinema 4D space, so the projectool don't understand clearly your input so you need to escape it by adding "" so something like: kernel_app_64bit.exe g_updateproject="D:\MAXON_CODE\Maxon Cinema 4D 2023_CODE\sdk" Cheers, Maxime.
  • Undo for InsertUnder() is not right. Why?

    python
    4
    4
    0 Votes
    4 Posts
    783 Views
    ferdinandF
    Thanks! Sorry, I am so careless that I ignore the message "Needs to be called before the change.". No worries, you are not the first one who trips over Undo call order, including myself at some point
  • Python. Cinema4d. All iterations in the Text value

    9
    2
    0 Votes
    9 Posts
    1k Views
    S
    @ferdinand thx very much! ill save this
  • create_nodematerial.py from Github not working

    r25
    5
    0 Votes
    5 Posts
    603 Views
    M
    Hi @bentraje I think there was a small misscommunication what was fixed on Github was the fact that the file does not contain the information of which Cinema 4D version they are working. We are not going to adapt our GitHub script to make it work for R25. If you want code that is going to work for R25, the only solution is to download the python SDK for R25. Cheers, Maxime.
  • Sample Code for Connecting Ports/Nodes?

    r25 python
    4
    1
    0 Votes
    4 Posts
    464 Views
    ManuelM
    hi, There are no particular reasons. Muting a connection is less intuitive than connect two nodes. If there was a function like Connect to mute the connexion, we would not have created that example neither. Cheers, Manuel
  • older documentation links?

    r25 python
    3
    0 Votes
    3 Posts
    349 Views
    B
    @fwilleke80 Gotcha thanks for the confirmation. So I guess they don't host it online? But man they are already using sphinx. They can easily have a button to switch to previous versions. But oh well.
  • Access Spline Field Parameters with XPresso

    python s26
    3
    0 Votes
    3 Posts
    779 Views
    I
    Thank you for the elaborate reply, it worked! (And helped me to better understand the desc id system)
  • Priority Delay on Stacking Skin Deformers

    r21 python
    16
    0 Votes
    16 Posts
    2k Views
    B
    Hi, Just checking if this is now resolved in the current version of C4D (2023).
  • Is it possible to change active view?

    python
    2
    0 Votes
    2 Posts
    554 Views
    ferdinandF
    Hello @lingza, Thank you for reaching out to us. In short, what you want to do is unfortunately not possible. To unpack things a bit, I understood your question as such that you have multiple view panels in your layout and each view panel contains multiple views. The screen below shows two view panels with four views each for example. [image: 1665048050441-screenshot-2022-10-06-at-11.20.38.png] You then want to toggle a view panel from showing all its views (depending on the panel layout) to singular one, e.g., "minimize and maximize" the Perspective view in the second panel. For that you wanted to use c4d.CallCommand(13640) and therefore need to set the active view (the view with the grey border). Internally, there is a non-public method called BaseDocument::SetActiveView which handles setting the selected viewport and one has more or less all tools in the Python SDK to replicate it (you more or less just have to set BIT_ACTIVE and send some messages). And while doing this will have some effect on the selection state of viewports, it will not be identical to what you can achieve with mouse interactions, and running then your CallCommand(13640) on such 'semi-selected' viewport will not have the desired effect. In the end, the viewport selection state is bound to a very specific call chain in our internal API. Which is probably the reason why the method BaseDocument::SetActiveView remains non-public. FYI: This is not a Python issue, the same applies to C++, I tried it there too, to the same effect. Cheers, Ferdinand
  • GetSplinePoint REVERSE

    python
    3
    1
    0 Votes
    3 Posts
    814 Views
    Caleidos4DC
    Thanks ferdinand I will treasure your help. Thank you very much!
  • Material and Shader Questions

    python s26
    3
    0 Votes
    3 Posts
    433 Views
    gheyretG
    @m_adam OK~ Thank you so much!
  • Cinema S26 and newer is not longer threadsafe for ObjectData?

    s26 windows c++
    2
    0 Votes
    2 Posts
    521 Views
    ferdinandF
    Hello @victor, Thank you for reaching out to us. While I am fairly confident that I understand your question, I am going to be very literal in my answer to avoid some ambiguities. Some Facts ObjectData was never 'thread-safe'. Or to be more precise, the classic API scene graph of Cinema 4D was never thread-safe (an ObjectData instance does not store any public data itself and therefore does not have to be accessed, i.e., falls outside of the notion of thread-safe or not). Some methods, as for example ObjectData::GetVirtualObjects, are never being called from the main thread and it is therefore forbidden for example to modify the scene graph or invoke EventAdd() or drawing calls from there. Some methods, e.g., ::Message(), are being called relatively often from the main thread and can therefore be used to execute things on the main thread. However, there is and never was any guarantee that ::Message() will always be on the main thread. You must still always check yourself with GeIsMainThread() or GeIsMainThreadAndNoDrawThread(). Some code could always send a message from any thread to your object. The fact that MSG_DOCUMENTINFO can now be broadcasted outside of the main thread is likely tied to async scene loading introduced with S26. The Problem with your Question You state that '[your] plugin requires third-party communications' and therefore assert that 'executing some functions on the main thread is necessary' for you. I do not understand what you mean by that. You should describe more precisely what you want to do in that message function. Do you want to modify scene graph data; add/remove objects, tags, shaders, etc. ? Do you want to modify your own global data? Do you want to communicate with a server or something like this? You should really clarify what your goals are and ideally share code with us either here or via sdk_suppport(at)maxon(dot).net. Otherwise it will be very hard to help you. Possible Solutions What the right solution is for you depends heavily on what you want to do. What however is not possible, is to force your ::Message method only being called from the main thread. Share Write Access to your own Global Data To do that, you should use a lock/semaphore, so that only one entity/thread at a time can access your data, e.g., write to a global log file or send data to a server. There are classic API and maxon API types which can help you with that. It is strongly recommend to use them over similar functions of the std library. Modify the Scene Graph You must defer the execution of your code to the main thread here. There are in principle two ways to achieve that. Defer by waiting: The simplest pattern is to simply store the notion that you want to do X on the main thread when you encounter the the state Y in a non-main thread. In the simplest form this could be a private field Bool _doX; on your object hook which you then set to true. The next time ::Message is being called and you are on the main thread, you then simply carry out doing X and then set the field back to false. The disadvantage of this approach is that you have no control over when X is actually carried out, as you must wait for something else calling your object hook on the main thread. The advantage is that you do not hold up everything else as with the second method. Defer with ExecuteOnMainThread: With this function you defer the execution of a lambda/delegate to the main thread. The advantage of this approach is that the changes are carried out immediately (at least relatively) and you can directly 'carry on' in your code. The disadvantage is that that the function is based on maxon::JobInterface, i.e., there is a queue of jobs on the main thread which are solved sequentially, and you might not be first in line. Also, this is by definition blocking. So, when you are inside a thread Y which has been optimized for speed, and you then defer the computationally heavy task X to the main thread, first wait for other things to be done, and then do your task X, the thread Y is waiting all that time for you and with it everything that relies on that thread. This does not mean that you should not use the function, but you should be careful. It could look something like this (untested pseudo-code): MyObjectData::Message(GeListNode* node, Int32 type, void* data) { // The #something event has happened, and we are not on the main thread. if ((type == ID_SOMETHING) && !GeIsMainThreadAndNoDrawThread()) { // We add a cube to the document of #node from the main thread. maxon::ExecuteOnMainThread([&node]() { iferr_scope_handler { err.CritStop(); return; }; BaseDocument* const doc = node.GetDocument(); BaseObject* const cube = BaseObject::Alloc(Ocube); if (!doc || !cube) return maxon::UnexpectedError(MAXON_SOURCE_LOCATION); doc->InsertObject(cube, nullptr, nullptr); }, maxon::WAITMODE::DONT_WAIT); } // Other code ... return SUPER::Message(node, type, data); } You could also use other more complex approaches here, but they are always just a variation of these two (e.g., use a MessageData or SceneHookData plugin). Cheers, Ferdinand
  • Can I get active things order with python?

    windows python s26
    8
    1
    0 Votes
    8 Posts
    2k Views
    DunhouD
    @ferdinand Thanks for the detailed explain I think DescriptionCustomGui is the best way to solve this for now . With learning furthur , maybe I will try a C++ version , but for me it's not time . Anyway , It is helpful for this techniclly explain and the example