Solved Detecting Rename

Hello,
Is it possible to get information about the event when an object has been renamed? I'm currently listening for the EVMSG_CHANGE Core Message but I get None when I print BFM_CORE_PAR1 and BFM_CORE_PAR2. I tried looking for other messages, but EVMSG_CHANGE seemed like the right one. I would like to find out what the object's name was before and after the change.

    def CoreMessage(self, id, msg):
        if id == c4d.EVMSG_CHANGE:
            for id, data in msg:
                if str(type(data))=="<type 'PyCObject'>":
                    pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
                    pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
                    data = pythonapi.PyCObject_AsVoidPtr(data)
                print id, data

        return True

Thank you!

@blastframe sorry no there is nothing for a GeDialog, if you are in a GeDialog, your best bet is within the GeDialog's CoreMessage, listen for EVMSG_CHANGE and figured out if the generator changed or not.

@indexofrefraction print will require a redraw as soon as possible, and most important this will consume all messages.
So is it nice? Not really but I guess you don't have other choices.

Cheers,
Maxime.

Hi,

I am not the biggest expert on Cinema's core message system, but AFAIK EVMSG_CHANGE is only being broadcasted for modification of the scene graph or similar events, not the modification of nodes.

Messages for the modification of nodes are being sent as atom messages (C4DAtom.Message) and there is unfortunately currently no way in Cinema to subscribe to such events from the outside. Cinema's closest thing to that would be C4DAtom.GetDirty, which will, among other things, allow you to track the dirty state of the data container (a.k.a. the attributes) of the node, but would have to be checked regularly by yourself.

But this all seems overly complicated for such a simple task, simply design an object that regularly checks the names of the nodes that it is meant to monitor. One solution could be a MessageData plugin with its timer method.

Also: I am also not quite sure what you are trying to do there with the PyCObject in your code. It just holds a void pointer, i.e. an address and a block size for a memory region. The type is mostly useless in Python itself and only comes in handy when you use Python as a glue-language between two C(++) applications (i.e. is heavily used by Python itself internally). You can technically parse some basic C-types with Python's struct if you know their memory location, but that won't work with anything more complicated.

Cheers,
zipit

MAXON SDK Specialist
developers.maxon.net

Hi @blastframe

To be more precise EVMSG_CHANGE is called when an EventAdd is processed, which is normally done after a SetName but not mandatory.

SetName actually set the dirty c4d.DIRTYFLAGS_DATA on the renamed element. Moreover, the MSG_NOTIFY_EVENT is also sent so that means any BaseList2D can receive a notification when the other object is renamed.
Here a short example with a Tag listening for the renaming of its host object.

import c4d

def message(msgType, data):
    if msgType == c4d.MSG_NOTIFY_EVENT:
        if data["eventid"] == c4d.NOTIFY_EVENT_SETNAME:
            renamedObj = data["bl"]

            print(renamedObj.GetName())


def main():
    obj = op.GetObject()

    if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_SETNAME):
        obj.AddEventNotification(op, c4d.NOTIFY_EVENT_SETNAME, 0, c4d.BaseContainer())

if __name__=='__main__':
    main()

Note that AddEventNotification is to be used with extreme care as you can screw up the Cinema 4D message system. so please only read the data and don't do infinite change (aka renaming the initial object, since it will trigger another MSG_NOTIFY_EVENT message and you can easily end with an infinite loop).

Finally, another way to achieve what you want is to have a list of tuples of object and associate name.
Then within a Timer check if the name changed by iterating this list.

Cheers,
Maxime

@zipit and @m_adam , thank you for the replies.

@zipit , I have no clue what the PyCObject code is doing: I found that code in a few threads on this forum for deciphering BFM_CORE_PAR1 and BFM_CORE_PAR2 from the CoreMessage. It doesn't seem to find any information.

@m_adam , is there a way to listen to NOTIFY_EVENT_SETNAME from a GeDialog? Sorry, I forgot to mention that I'd be doing this from a Command Plugin and a GeDialog.

Thank you!

Can I ask if it is possible to get a notification when

  • the generator bit gets changed?
  • the visibility / render bits get changed?

there doesnt seem to be a NOTIFY_EVENT for these actions...

For the generator bit, this can be somehow done via

import c4d

def message(msgType, data):
    if msgType == c4d.MSG_NOTIFY_EVENT:
        if data["event_data"]["msg_id"] == c4d.MSG_DEFORMMODECHANGED:
            print(data)



def main():
    obj = doc.GetFirstObject()

    if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE):
        obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer())

if __name__=='__main__':
    main()

The main issue is it's triggered only after an EventAdd so this means most of the time you will not get the change immediately.

Regarding the visibility, this is unfortunately not possible, since SetEditorMode/SetRenderMode only do a SetDirty(DIRTYFLAGS::MATRIX) internally. And the dirty state is not monitored by the Event Notification system.

One side note it's possible to use MSG_DESCRIPTION_POSTSETPARAMETER like in the snippet bellow, but this message is sent by the Attribute Manager when a parameter is set, so that means if you change the value within the Attribute Manager of the Editor display mode, the change will be monitored, but if you change the mode via the Object Manager, which directly use SetEditorMode, then the message is not sent.

import c4d

def message(msgType, data):
    if msgType == c4d.MSG_NOTIFY_EVENT:
        if data["event_data"]["msg_id"] == c4d.MSG_DESCRIPTION_POSTSETPARAMETER:
            if data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_VISIBILITY_EDITOR):
                print("changed editor")
            elif data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_VISIBILITY_RENDER):
                print("changed render")
            elif data["event_data"]["msg_data"]["descid"] == c4d.DescID(c4d.ID_BASEOBJECT_GENERATOR_FLAG):
                print("changed generator")


def main():
    obj = doc.GetFirstObject()

    if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE):
        obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer())

if __name__=='__main__':
    main()

Cheers,
Maxime.

@m_adam Hi Maxime, any notes on the GeDialog question prior to the generator question: Is it possible to listen to a rename event from a GeDialog in a Command Plugin?

@m_adam :

thanks, i need it to work when editing live in the object manager. i found a little hack for the generator flag snippet:
like this, i immediately get a msg if i change the generator flag in the object manager. without the print statement it does not work.
do you understand this? i guess its not recommended? .-)

just put that script in a python tag on an object with a generator switch (instance for example)

import c4d

def message(msgType, data):
    if msgType == c4d.MSG_NOTIFY_EVENT:
        if data["event_data"]["msg_id"] == c4d.MSG_DEFORMMODECHANGED:
            obj = op.GetObject()
            print(obj.GetName(), obj[c4d.ID_BASEOBJECT_GENERATOR_FLAG])

def main():
    obj = op.GetObject()
    if not obj.FindEventNotification(doc, op, c4d.NOTIFY_EVENT_MESSAGE):
        obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE , 0, c4d.BaseContainer())
    print(""), # DIRTY HACK :)

if __name__=='__main__':
    main()

@blastframe sorry no there is nothing for a GeDialog, if you are in a GeDialog, your best bet is within the GeDialog's CoreMessage, listen for EVMSG_CHANGE and figured out if the generator changed or not.

@indexofrefraction print will require a redraw as soon as possible, and most important this will consume all messages.
So is it nice? Not really but I guess you don't have other choices.

Cheers,
Maxime.

This post is deleted!

Hello @blastframe,

without any further questions or replies, we will consider this topic to be solved by Monday and flag it accordingly.

Thank you for your understanding,
Ferdinand

MAXON SDK Specialist
developers.maxon.net