Unified Component Development in GH1 and GH2

Dear @DavidRutten,

I am looking to establish a framework that facilitates the development of components for both Grasshopper1 and Grasshopper2. The goal is to create a unified Component class that can be converted into either a GH1 or GH2 component.

While this approach functions well for GH1, there are two problems when implementing it in GH2:

  • The ObjectProxy class is sealed, preventing inheritance and thus hindering dynamic component creation.
  • The static ObjectProxies class lacks a direct mechanism to add objects of type ObjectProxy.

It would be great if the sealed modifier could be removed from the ObjectProxy class or if an IObjectProxy interface could be introduced.

Additionally, it would be helpful to include an Add(ObjectProxy proxy) method in the ObjectProxies class.

What do you think?

– Clemens

1 Like

I worry about making this system too open. One of the main goals for improving plug-in experience (from the user’s point of view, not the developer point of view) is to have a much more reliable auto-install-and-uninstall system. It already pretends to work in GH1 but very often it just fails to find the required plugin on the Yak PackageServer. If I allow the insertion of ghost components into files, then even that lame approach falls apart, as the component ID will never be registered with any Yak server because it only exists at runtime.

Sadly any workaround (like for example generating an assembly in memory with the required component classes) will have the exact same drawbacks as opening up the object registration…

Do you have a set of components that is unknown at compile time? Or could you generate class stubs for all components in a script as part of your build process?

Why not to let the user decide about this? By default GH do not allow unknown components on documents, but let it be changed from settings with all the warnings you want. If someone opens a file with auto-generated unknown components and this setting off, do not insert them on the doc or alert the user if they trust the author.

In the end, developers will find dirtier ways of similar functionality which end up with worst user experience.

That’s a possible solution to a somewhat different problem though. All non-standard components must be considered equally suspect, and the Sandbox mode in GH2 is a first stab at shielding users from the unwanted (not necessarily malign) side-effects of running foreign files.

However the problem @cp1 has is that he wants to add his components in a way which makes it harder for me to provide a smooth experience for those who are happy to install non-standard plugins if the need arises.

There probably is a solution out there somewhere which is acceptable to both of us. I already added the GrasshopperIO.ICustomIoId interface in response to a vaguely similar request. By implementing this interface you can get away with not attaching an IoIdAttribute to your component classes. But it also potentially messes with Yak integration.

Hi David, thank you very much for your answer!
– Clemens

Hi Clemens & David,
I am late to the discussion but… @DavidRutten we are impacted by this, as all our (hundreds of) components are generated at runtime from reflection of our API. I ended up at the same point than Clemens when I had a first try at porting our plugin for GH2, but without the ability to register proxies dynamically as in GH1, we cannot port anything.
I would be keen to discuss this at the GH2 dev workshop in London in a few days.
Best,
Thibault

PS: we cannot use Yak to install our packages at all, our GH plugin is only a small part of our software framework, that needs to be installed separately, the GH plugin for us is merely a loader of other HAL plugins and related content.

I just had another go at this, and managed to get around things with a few hacks, but very little changes would allow the scenario I described above to be supported without having to mess around too much.

    1. have an overridable harvesting method in Plugin, so developers can add custom logic in the plugin loading. Otherwise, just adding the possibility to have a plugin loader class as in GH1 would do (maybe there is one already, I may have overlooked it). I circumvented this by subscribing to the PluginServer.PluginLoaded event to trigger the custom loading of my components.
    1. have a way to pass an IoId at runtime, instead of using a reflected class attribute. This can be discarded if the next point is addressed:
    1. as suggested by Clemens initially, unsealing ObjectProxy, making GeneralProxy.Emit overridable, and a public method to register a proxy instance in ObjectProxies are the last missing points.

With a bit of Roslyn black magic, it was straightforward to mimic the compilation of components as if they were part of the plugin assembly, so that I could inject them as in GH1:


This is a basic exemple, just to illustrate the issue and solution. I do think this should be supported, as it is probably the only way to have a shared codebase + thin wrappers to publish components in GH1 and GH2 (without having to redo hundreds of classes manually).

Best, Thibault