id PluginMessage () when the scene loaded
-
Hello!
I need to find the Message ID when the scene has already loaded, so that after that I can run the plugin that will work with objects on the scene, it is important to make this plugin automatic, that is, without clicking on the button in the plugin gui. As it should be: Cinema4d started > Scene loaded > plugin started > plugin get objects > plugin work with objects. Please help, Google does not help -
I don't think this will work for a Python plugin, but with C++ you can provide a SceneHook and use message MSG_DOCUMENTINFO_TYPE_LOAD
-
@C4DS, Hi!
it is very sad. I don't really want to rewrite the plugin from Python to C++ -
@C4DS said in id PluginMessage () when the scene loaded:
I don't think this will work for a Python plugin, but with C++ you can provide a SceneHook and use message MSG_DOCUMENTINFO_TYPE_LOAD
Maybe there is another way to start the plugin automatically? Mb is not PluginMessage ()
-
hi,
you can see in this thread that it's not possible with python.
But maybe you can use another workflow. You can have another plugin asking for a directory, load every document on that directory, call your script that will work on the document, and close the document.You can only write the SceneHookData with c++ and that SceneHookData will call your python command so you don't need to rewrite it.
Cheers,
Manuel -
@m_magalhaes, Hi!
Thanks for the answer, I will try this and answer later. -
You can only write the SceneHookData with c++ and that SceneHookData will call your python command so you don't need to rewrite it.
Hi!
Do you have examples of a plugin written with SceneHookData? I am more proficient in python than c ++ -
@m_magalhaes, Hi, can you answer me? plz
-
Hi,
if my memory does not betray me,
MSG_DOCUMENTINFO
is being broadcasted to all nodes in the scene. So if you want to stay in Python, you could simply hijack a node type. One promising candidate could bePreferenceData
, although I cannot guarantee that Cinema will also send document notifications to these nodes, since they are not part of a scene.Cheers,
zipit -
hi,
Sorry for the delay.we have this example.
The most important is ou c++ documentationyou can see an example in the BaseDocument Manual
class pc12835_scenehook : public SceneHookData { public: static NodeData* Alloc() { return NewObjClear(pc12835_scenehook); } Bool Message(GeListNode* node, Int32 type, void* data) override { if (type == MSG_DOCUMENTINFO) { DocumentInfoData* const msg = static_cast<DocumentInfoData*>(data); if (msg == nullptr) return false; // switch message sub-type switch (msg->type) { case MSG_DOCUMENTINFO_TYPE_LOAD: { ApplicationOutput("document is loaded"_s); break; } case MSG_DOCUMENTINFO_TYPE_UNDO: case MSG_DOCUMENTINFO_TYPE_REDO: { ApplicationOutput("undo or redo done"_s); break; } } return true; } return SceneHookData::Message(node, type, data); }; };
As @zipit said, the message is broadcast to all
NodeData
so using a PreferenceData.
We have an example on github but you don't need all that code.
After trying it myself, i couldn't make it work. It seems that theMessage
function is never called.Cheers,
Manuel -
@m_magalhaes Hi, where in this code does the script start to run and call the python code? Or did I misunderstand something?
-
hi,
sorry I was focused on calling a command and not a script.Even if it's pretty simple, it's not as simple as i expected to run a python script, sorry about that.
Be careful that you need to create the script and relaunch c4d to be able to find it by its name.The idea is to retrieve the ID of the script and use callCommand to execute it. (as you can do with any commandData IDs)
you can retrieve the ScriptList with GetScriptHead witch return a GeListHeadSo you can retrieve the first with
GetFirst
and compare the name.
If you find one, you can simply return it's IDs using GetDynamicScriptID and return it.You now just have to use
CallCommand
with this ID. (be aware that this CallCommand will create an undo step in the undo stack)So your script will be executed when a new document is loaded.
#include "maxon/apibase.h" #include "maxon/errorbase.h" #include "maxon/errortypes.h" #include "maxon/file_utilities.h" #include "maxon/application.h" #include "c4d_general.h" #include "c4d_commanddata.h" #include "c4d_baseplugin.h" #include "c4d_scenehookdata.h" #include "c4d_baselist.h" static Int32 GetScriptID(const maxon::String& scriptName) { iferr_scope; // check all script // Retrieves the script head BaseList2D* scriptHead = static_cast<BaseList2D*>(GetScriptHead(0)->GetFirst()); // for all script for (BaseList2D* script = scriptHead; script != nullptr; script = script->GetNext()) { // retrieves the name of the script maxon::String name = script->GetName(); // if the name match the argument, return the id of the script if (name.IsEqual(scriptName)) return GetDynamicScriptID(script); } // return NOTOK if no script founded. return NOTOK; } class pc12835_scenehook : public SceneHookData { public: static NodeData* Alloc() { return NewObjClear(pc12835_scenehook); } Bool Message(GeListNode* node, Int32 type, void* data) override { if (type == MSG_DOCUMENTINFO) { DocumentInfoData* const msg = static_cast<DocumentInfoData*>(data); if (msg == nullptr) return false; // switch message sub-type switch (msg->type) { case MSG_DOCUMENTINFO_TYPE_LOAD: { // define my script name maxon::String scriptName = "myscript"_s; // search the ID of the scrip const Int32 scriptID = GetScriptID(scriptName); // if the script have been founded, execute it. if (scriptID != NOTOK) CallCommand(scriptID); break; } case MSG_DOCUMENTINFO_TYPE_UNDO: case MSG_DOCUMENTINFO_TYPE_REDO: { ApplicationOutput("undo or redo done"_s); break; } } return true; } return SceneHookData::Message(node, type, data); }; };
Of course you need to register your sceneHookData with RegisterSceneHookPlugin
Cheers,
Manuel