Best way to programmatically create "listener" tag
On 30/05/2018 at 13:07, xxxxxxxx wrote:
Cinema 4D Version: R19
Platform: Windows ; Mac OSX ;
I am looking to programmatically create a (hidden) tag, which is assigned to polygon objects.
The only purpose of this tag is to listen to MSG_POLYGONS_CHANGED and MSG_POINTS_CHANGED, and inform another part of the plugin.
Now, I don't want the user to take actions to create these "listener" tags manually.
As such, I use a MessageData to listen to EVMSG_CHANGE and iterate over the current active objects. When an active object does not have a listener tag, I create one using BaseObject::MakeTag.
For testing purposes I have left the tag visible. I can thus select such tag and delete it.
As a result of the deletion an EVMSG_CHANGE is sent, and automatically a (new) tag is created and assigned.
However, if I then press the undo button, the deletion of the tag is reverted and I end up having two tags.
I could check during the EVMSG_CHANGE if the active object has more than one listener tag, and remove all but one.
But isn't there a better solution?
How do people create their hidden control tags?
Note, when the tag is hidden, the user cannot select and delete it, but deletion could still occur via scripts, etc ...
So, how to prevent ending up with multiple of these (hidden) control tags?
On 31/05/2018 at 09:08, xxxxxxxx wrote:
If you want only one instance type of your tag per object you simply have to register it without the flags TAG_MULTIPLE then the last one will be used each time.
A side note is not usual to have tag created to arbitrary objects. Even if you don't do anything wrong here, is not the main purpose of tag, which is just here to store data.
So you may encounter other issues.
On 31/05/2018 at 12:19, xxxxxxxx wrote:
Thanks for the reply, but limiting a tag to a single instance doesn't simply work by omitting the TAG_MULTIPLE attribute when registering the plugin.
I do get following message (as message box and in console window)
A problem with this project has been detected: Object "Cube" - Tag 1888898 present too often. Please save and contact MAXON Support with a description of the last used commands, actions or plugins.
The Tag ID 1888898 is a dummy ID I am currently using for RnD purposes.
I am avoiding the above error message by allowing multiple instances. Not that I want multiple instances, I just don't want the error message to appear in the first place.
In another thread I discussed the need to detect polygon changes, and one of the solution was to create a tag listening to message MSG_POLYGONS_CHANGED. As this message is only sent to tags, there doesn't seem to be any other way than to create this "listener" tag.
I understand the purpose of most tags is to carry data, but I am sure there are a few (or more) that do more than just carry data. Or even some that do things without actually carrying data.
Say, for instance, the "Look at camera" tag ... does this one store any particular data, or is it not simply "listening" to camera changes and modifying the hosting object as a result?
So, not really different from the purpose of my own tag, I am listening to MSG_POLYGONS_CHANGED and modify the hosting object as a result.
On 02/06/2018 at 02:18, xxxxxxxx wrote:
Hi Daniel, unfortually you are right and the message can't be removed.
I will invest more time monday to find a solution.
On a side note if you want to know how the Look-at tag work you have the full code example in our sdk example here
On 06/06/2018 at 05:23, xxxxxxxx wrote:
First of all sorry for the delay.
I would like to remind you that your case is very uncommon for Cinema 4D, and C4D was not designed to handle object creation within EVMSG_CHANGE.
The c4d way is to handle undo when inserting any kinds of BaseList2D in a scene, but in your case is not possible and a no sense.
With that said, the best way for you would be to create tags (with TAG_MULTIPLE) with a timestamp stored in their basecontainer.
Then in TagData::Execute or even MSG_UPDATE check if the object holds another tag and mark itself as to be deleted if it's the older one and send a Message to your SceneHook. (Do not delete node in a threaded Context)
And finally in your SceneHook, you can store an array of all tags you inserted, and then check if one of the tags needs to be deleted.
On 06/06/2018 at 21:45, xxxxxxxx wrote:
Great, thanks Maxime.