IDProperty addon

Hi guys,

I recently finished an addon that provides IDProperty support. For those of you who don’t know what that is, it’s a property (like IntProperty or StringProperty), but the value of this one can be another object! Before, you had to use a StringProperty and enter in the name of the object you wanted to point to, and then pray that the name never changed :wink:

I built it for my own personal use, but I spent some time cleaning it up for others to use. Let me know what you think

Oh, wow, this is awsome.
I will try to implement this with the Blembic importer.

Yeah, IdProperties are definitly very important and would be a nice to have!
It was a good idea to make a generic implementation as addon :slight_smile:

While working on the Animation Nodes addon I also had to find a solution to the problem.

These were the goals my system had to met:

  • It has to work with copying objects (people do that all the time…)
  • It has to be fast in the common case (“Make the common case fast” paradigm). Your system seams to have the complexity O(n) in all cases. I wanted to have O(1) most of the time, because many users (including me) of the addon have a LOT of objects because of the Object Instancer node (which had its own difficulties -.-)

So here are some of my ideas that are currently implemented in AN. Maybe it helps you to improve your addon and overcome the limitations.

Everything is based on the fact (took me a long time to get this idea -.-) that the python hash function is constant for an object within one session (until you close Blender). When you duplicate an object, the new object will have another hash. The hashes are internally used to compare objects.

  1. Instead of storing a custom identifier I only store the name of the object in a StringProperty.
  2. In the background there is a dictionary that maps object names to the hashes of the objects.
  3. When you want to get the object you can first check wether the name exists (this is the common case)
  4. If it doesn’t exist you lookup the hash in the dictionary and iterate through all objects until you find the object again. (this is the uncommon case and can be slower).

Here is some of the code I use in my implementation:
https://github.com/JacquesLucke/animation_nodes/blob/master/utils/id_reference.py
https://github.com/JacquesLucke/animation_nodes/blob/master/sockets/object.py#L28-L34

This system has only one limitation. When you rename two objects at the same time and one object will have the old name of the other object…
(Problems can also occure when object names exist twice due to linking… But many addons have problems with that anyway, so I don’t care… It’s up to the user to not let this happen)

I hope that helps or someone else :slight_smile:

Bump… added GroupIDProperty and generalized the id code to work with any ID type, not just Objects.

Thanks for the feedback Jacques :slight_smile:

You’re right, I am not a fan of the O(n) complexity for lookups in my system. Though I have found in practice that even when the scene has 10k objects, it still takes under 1/100th of a second to resolve the the IDProperty field. And since only the selected object will have its field updated, the object resolution isn’t noticeable. But yes, it does bother me that it is not O(1) :wink:

I have a few questions about your setup. What happens if someone renames an object (breaking the link), then saves and reverts the file? I am imagining the code will not be able to find the object because both the name and the hash are different?

I am looking into ways of running a background thread that periodically maintains a cache of id -> weakref(object), as well as resolving id conflicts, but I don’t have an experience with threads accessing/mutating the blender context. I’m hoping it Just Works™

Good.

Yeah I like to discuss about this thing, and maybe there are better solutions than mine. I mean it depends on what you want to use it for. I guess until this is supported by Blender itself (not sure if that will happen…) all we can create are leaky abstractions.

While 1/100th of a second might be fast for you it is quite slow for me.
For the sake of the argument let’s assume that it takes 1/1000th of a second for one object. In the Animation Nodes you can create lists of objects. The node for this looks like so:


Now let’s say someone uses this node with 50 objects (yes people do that quite often). That means to execute this node once would take 50/1000=1/20th of a second. And remember, this node is only for getting the references, no calculation has been done so far (and normally you want to animation something :smiley: ). This is wayyyy to slow for any realtime feedback. By default the node tree is executed roughly 20-30 per second… You see where this goes…
With my implementation I resolve 100 object sockets within 0.1ms.

Well, I’m not absolutely sure what you mean. When the object socket recognizes that the object name doesn’t exist anymore it will immediatly remove or replace the name with the new one.

Hm not sure if a background thread works in Blender… To be honest I never did something with the weakref module. But sounds like a good idea…

Well, I’m not absolutely sure what you mean. When the object socket recognizes that the object name doesn’t exist anymore it will immediatly remove or replace the name with the new one.

Yes but only if the nodes are evaluated before the file is reverted, right? If the last thing I do is rename an object, then close Blender, then your object socket doesn’t have time to resolve the object. When the file is re-opened, aren’t the hashes and the names referenced by the object socket are broken? I actually just tried to do this with your addon, but it did not break. What triggers the animation node to update (and therefore look for the correct object) when the name of the object is changed?

Anyways, not trying to criticize your setup, as it sounds like it works well :slight_smile: And my setup seems to not be ideal for your system unfortunately. I will try to continue to improve this…

Yes that is right.
I just checked this again and found a small mistake by me. A typical case of “It’s not a bug, it’s a feature” :smiley:
I cleaned this up now. I use the bpy.app.handlers.scene_update_post handler to update the object (and spline) sockets if needed. This function is executed 20-30 times per second.
this way you don’t have time to close Blender after you renamed the object. If you manage to close Blender so fast (with a script or so) the links would be broken, yes.

Btw: https://developer.blender.org/D113

Bump. I’m super happy to say there was a major refactoring to remove all previous limitations. Lookups are now O(1), and we support multiple ID types.

http://i.imgur.com/oCbutrk.png

Jacques, I used a hybrid of your solution if keeping a lookup table of object hashes. However, I modified this approach in the following way: I actually use two lookup tables… one for id => hash, and another from hash => name. They’re populated on file load, and kept up to date whenever an ID property is set. ID properties still store an object’s unique id under the hood, which I think is more reliable than a hash because it persists between file loads. But the hash is necessary because it is never non-unique. So the two tables combined allow us to be pretty robust. I also shamelessly ripped off your eyedropper :wink: Also added a “show selected selected” op to the buttons.