Solved Best way to detect an object has been deleted?

I have a plugin that created a Cloner and insert planes as children of that cloner. After that I update the Cloner Count.
However, when the user deletes a plane ( a child of that cloner), the Cloner count must be updated.

What is the best way to detect an object has been deleted and I can update the Cloner count?

Hello @pim,

thank you for reaching out to us. The proposed solution of @fwilleke80 sort of works, but has its problems in Python. There is no type BaseLink in Python and you can therefore not use it directly. You can add a parameter of type DTYPE_BASELISTLINK to a BaseList2D of your choice and then store there the reference to the node. But that always requires a node where you are okay with "polluting" its GUI in this manner. You could of course hide these parameters in the UI, but that all could come a bit messy, especially when it is more than one parameter to reference.

There are two alternative solutions:

  1. EVMSG_CHANGE: This core message is being sent when a document has changed. This includes, but is not limited to, objects being removed. You get here no further information except for the fact that EVMSG_CHANGE has occurred. You must determine yourself if an event x, e.g., the object with the name "foo" has been deleted, has occurred. One usually must deal with the UUID markers of nodes when doing something like this. We talked often about UUID markers on this forum, for example here I went over the whole approach.
  2. BaseList2D.AddEventNotification: With this method you can let yourself be informed about events that happen to a specific node, including NOTIFY_EVENT_REMOVE. I showed how to use this internal method here.

When we compare the two approaches, we can note a few drawbacks for each of them:

  1. EVMSG_CHANGE:
    • Requires a MessageData plugin, or a GeDialog/GeUserArea to receive the core message in the first place.
    • The message itself is very broad, and one must do substantial work to narrow down an event. If done naively, this can become a substantial bottleneck.
    • So, when you want to be informed inside an ObjectData implementation O if a node n has been removed, you would implement a MessageData M, which listens for EVMSG_CHANGE, then traverses the scene to check if N is still there, and finally informs all instances of O by sending a MSG_BASECONTAINER to them with the event data.
    • All in all, this can be quite a bit of work, but it is the most robust approach when executed properly.
  2. AddEventNotification:
    • Requires access to some kind of NodeData, e.g., an ObjectData, implementation because without access to a NodeData.Message to receive the event notification, adding an event notification is meaningless.
    • This method family is internal for a reason. When used improperly, it is easy to crash or freeze Cinema 4D with it.
    • NOTIFY_EVENT_REMOVE is unfortunately very literal in its event handling. When we have the element hierarchy root->a->b and we register for NOTIFY_EVENT_REMOVE for b, we will only be informed when b.Remove() is being called, but not when a.Remove() is being called, although both events have effectively the result that b is not part of the element tree root anymore.

What to do concretely depends on your plugin. Please share code and details about your project, as answering your question will otherwise be speculative.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

You could keep a BaseLink to the object.

But, shouldn't the Cloner notice anyway that its child objects are gone?

www.frankwilleke.de
Only asking personal code questions here.

I am not sure what you mean with a Baselink?

A Cloner, imo, does not notice when a child is added or deleted.

I guess there is (somewhere) a message that signals a deletion?

Hello @pim,

thank you for reaching out to us. The proposed solution of @fwilleke80 sort of works, but has its problems in Python. There is no type BaseLink in Python and you can therefore not use it directly. You can add a parameter of type DTYPE_BASELISTLINK to a BaseList2D of your choice and then store there the reference to the node. But that always requires a node where you are okay with "polluting" its GUI in this manner. You could of course hide these parameters in the UI, but that all could come a bit messy, especially when it is more than one parameter to reference.

There are two alternative solutions:

  1. EVMSG_CHANGE: This core message is being sent when a document has changed. This includes, but is not limited to, objects being removed. You get here no further information except for the fact that EVMSG_CHANGE has occurred. You must determine yourself if an event x, e.g., the object with the name "foo" has been deleted, has occurred. One usually must deal with the UUID markers of nodes when doing something like this. We talked often about UUID markers on this forum, for example here I went over the whole approach.
  2. BaseList2D.AddEventNotification: With this method you can let yourself be informed about events that happen to a specific node, including NOTIFY_EVENT_REMOVE. I showed how to use this internal method here.

When we compare the two approaches, we can note a few drawbacks for each of them:

  1. EVMSG_CHANGE:
    • Requires a MessageData plugin, or a GeDialog/GeUserArea to receive the core message in the first place.
    • The message itself is very broad, and one must do substantial work to narrow down an event. If done naively, this can become a substantial bottleneck.
    • So, when you want to be informed inside an ObjectData implementation O if a node n has been removed, you would implement a MessageData M, which listens for EVMSG_CHANGE, then traverses the scene to check if N is still there, and finally informs all instances of O by sending a MSG_BASECONTAINER to them with the event data.
    • All in all, this can be quite a bit of work, but it is the most robust approach when executed properly.
  2. AddEventNotification:
    • Requires access to some kind of NodeData, e.g., an ObjectData, implementation because without access to a NodeData.Message to receive the event notification, adding an event notification is meaningless.
    • This method family is internal for a reason. When used improperly, it is easy to crash or freeze Cinema 4D with it.
    • NOTIFY_EVENT_REMOVE is unfortunately very literal in its event handling. When we have the element hierarchy root->a->b and we register for NOTIFY_EVENT_REMOVE for b, we will only be informed when b.Remove() is being called, but not when a.Remove() is being called, although both events have effectively the result that b is not part of the element tree root anymore.

What to do concretely depends on your plugin. Please share code and details about your project, as answering your question will otherwise be speculative.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

Thanks again for the great explanation.
I guess I will go for a different workflow then.