User objects do not update

Hello, I am struggling to find the best way to reuse components in my scripts.

I am working on a script that uses many externally referenced ghclusters. These clusters appear throughout all levels of the script: on the highest level (i.e. the main GH file) but also inside other clusters. Because these ghclusters are externally referenced, I can make an update to the base file, and then every instance of that cluster knows that a newer version exists, and I can update them (manually).

The point is that when I distribute this script to other users, the end users will not have the directory available where we stored the externally referenced clusters during development. So I would like to package and distribute the clusters with the script. Ideally I would like to use a relative path reference, but that does not seem to be possible.

I also did a test with just using simple (unreferenced) ghclusters: create a cluster ‘A ‘ in the main GH script. Then create another cluster ‘B‘ where you use that other cluster ‘A‘. Then go back to the main script, make some changes to A, save and close. Then see if the version of ‘A‘ inside ‘B‘ has updated, but that doesnt work.

I spoke with AI and they proposed to use UserObjects. I could package a bunch of UserObjects and distribute them with the script. Then ask the end users to copy the userobjects to their userobjects folder, and it should work. So I did a small test, trying the same thing as described above: make a UserObject, use it in a main GH script, also use it inside a cluster. Then make some changes to the userobject (open, make changes, save and close) and then see if it has updated in the script and in the cluster. The answer is NO (!!).

For starters, I see that the userobject file in the userobjects folder doesnt even update, as the ‘Date modified‘ field doesnt change after I made changes. This confuses me so much. How am I supposed to do this?

I read this post (Updating user objects - Grasshopper - McNeel Forum) and they say that you should manually delete the old userobject, create a new one manually, then replace all instances of the old versions with the new version manually. Is that really the case?

The thing is that the externally referenced ghclusters (kind of) work the way I want to (except I dont like the manual updating). Now I just want it to work with something that is distributable.

What would you guys advise? How do you do this?

Many thanks in advance

I tried to rewrite my post to make it a bit more clear. But somehow I got an error. Therefore, here is the further elaborated post (hopefully a bit more clear)

——————————-

Hello, I am struggling to find the best way to apply reuseable components in my scripts, and distribute those together with the script.

I am working on a script that uses many externally referenced ghclusters. These clusters appear throughout all levels of the script: on the highest level (i.e. the main GH file) but also inside other clusters, up to multiple levels deep. So for example a ghcluster ‘A‘ can be on the main canvas, but also inside another cluster ‘B‘, or inside a cluster ‘C‘ that is inside ‘B‘, etc.

To go for the best maintainability, I have been using externally referenced ghclusters, where I export and reference clusters to/from a central folder. The advantage of this method is that if I want to change a cluster that appears in multiple places, I can open one instance of it, make some changes, save, and then every placed instance of that cluster knows (and shows) that a newer version exists, after which you can update to the latest version in one click. This is almost ideal. Better would be i.m.o. if it would be automatically updated, but OK.

Now comes the issue that I want to distribute this script to other users. Those users do not have access to the directory where I stored the externally referenced ghclusters (which is basically a dev environment). So ideally I would like to package the clusters and distribute them with the script.

This is where non-externally-referenced clusters sound better on paper, as they are stored inside the gh script itself. So you dont have to distribute them separately. However, they have the big big downside that I cannot achieve the maintainability that I described above. To describe a simple test : create a cluster ‘A ‘ in the main GH script. Then create another cluster ‘B‘ in which you copy that other cluster ‘A‘. Then go back to the main script, make some changes to A, save and close. Then open the ‘B‘ cluster and see if the version of ‘A‘ inside ‘B‘ has updated, it doesnt. Having to maintain this manually is for me a big no go. You will never know if the version of the cluster you are looking at is the latest version or not. Which is why I am using the externally referenced clusters.

Now, externally referenced clusters are referenced using an absolute file path. Which is visible if you hover over the cluster. Ideally, if a relative file path would be a possibility, this would solve my issue. As I could then just package the clusters in a folder next to the script, et voila. But unfortunately relative file paths do not seem to be possible.

I have been considering to start transforming the ghcluster objects into ghuser objects (UserObjects). My idea was that I could package a bunch of UserObjects and distribute them with the script. Then ask the end users to copy the userobjects to their userobjects folder, and it should work.

BUT I did a small test, trying the same thing as described above: make a UserObject, use it in a main GH script, also use it inside another cluster. Then make some changes to the userobject (open, make changes, save and close) and then see if it has updated in the script and in the cluster. The answer is NO (!!). This is confusing me big time.

First thing I notice is that the userobject file in the userobjects folder hasnt even updated, as the ‘Date modified‘ field didnt change after I made the changes.

I read this post (Updating user objects - Grasshopper - McNeel Forum) and the following quote by David Rutten is very clear, but really surprises me : ‘User objects do not update. They don’t even remember they are user objects. It’s just regular objects with some non-standard properties set.‘

Reading that post further it seems like when you work with userobjects that are still ‘under development‘, every time you make a change, you need to manually delete the old userobject, create a new one manually, then replace all instances of the old versions with the new version manually. Is that really the case? This would mean that user objects are actually not at all something I can use in my case.

OK, so lot of text, maybe not very to the point. I guess my question is, what would you advise me in my case, to achieve the maintainability and distributability that i want ?

The thing is that the externally referenced ghclusters (kind of) work the way I want to (except I dont like the manual updating). Now I just want it to work with something that is distributable.

What would you guys advise? How do you do this?

Many thanks in advance

It sounds like you’re trying to avoid making a plugin and trying to solve problems that are addressed by releasing a plugin.

One thing that does stand out - why do you need to distribute the cluster? Why not share the whole script where the references can be to the new cluster and avoid shipping any user objects at all? (Although, how often is this cluster really changing?)

Also, you know if your clients are even half competent with GH, they can unlock the clusters themselves? If you’re actually shipping IP, clusters are not the way to do it.

The added benefit is that your scripts will work many times faster if you compile your own components

Hi, many thanks for your response.

You are saying:

It sounds like you’re trying to avoid making a plugin and trying to solve problems that are addressed by releasing a plugin.

That could be true. But my understanding about plugins is that they can only contain C# code. I would prefer to have components that can be edited quickly and easily when needed, without writing textual code. This plugin or tool is still under heavy development. We want to start using it in projects already, but I’m sure that a lot of changes will still need to be made while using it for the first few times. That’s why I consider clusters a bit more fitting for this situation.

why do you need to distribute the cluster

Why not share the whole script where the references can be to the new cluster

This sounds interesting, but I dont understand your suggestion fully. If you say ‘where references can be set to the new cluster’ what do you mean exactly? How would that work? If you mean that it is possible to point the script’s cluster references to a specific folder, that would be great. Is this possible??

As said, the clusters were created in a dev environment, unavailable to end users. I would like to expose the clusters in a public folder and point the script to it, if that’s possible, that would be great.

how often is this cluster really changing

Im sure there wil be many changes to the script and clusters in the first period of using the script.

Also, you know if your clients are even half competent with GH, they can unlock the clusters themselves?

Yes Im aware of that and that is fine.

If you’re actually shipping IP, clusters are not the way to do it.

What is IP?

The added benefit is that your scripts will work many times faster if you compile your own components

That’s noted, thank you.

Thanks for your help. Looking forward to futher response.

Fair enough, I think C# might look daunting, but it sounds like it will solve more problems than it creates in your case.

For sharing the script, I mean that you don’t need to have the user objects on your computer at all to be able to open files that use them - this makes me wonder why not ship the whole script, with the clusters included but everything is in the grasshopper file, they’re not adding other objects to their libraries or worried about version control - they just download one single Gh file that you keep updated.

IP is Intellectual Property.

Still I’m a bit confused by what you mean that the clusters were created in a dev environment or what the end users are really doing - it’s possible that you Grasshopper Player might come in useful or to use DataInput/DataOutput to isolate parts of scripts - it’s harder to help without knowing what they’re doing, but I’m fairly certain that implementing a rudimentary version control with clusters is not going to be the most effective solution

Hi thanks for your response and for the information. I have decided to keep it very simple for now. Just internalise all the externally referenced clusters. And accept that whenever one of those clusters changes, I will need to manually update all instances of them, throughout all layers of the script.

Thanks