GlitchEnzo / NuGetForUnity

A NuGet Package Manager for Unity
MIT License
3.25k stars 319 forks source link

What is advised for Unity package using Nuget dependencies? #669

Open camille-avatarmedical opened 2 months ago

camille-avatarmedical commented 2 months ago

Hi,

In my company we use NugetForUnity which works great for Unity projects. We also try to split our code into reusable parts for which we use Unity packages. I wonder what the current way to create a Unity package that use a NuGet dependency seamlessly?

If that not possible do you have any experience to share to deal with this situation?

igor84 commented 2 months ago

I don't know of any way. In my company we also split our reusable code but into nuget packages so we are using NugetForUnity both for our internal and external packages and have no problem expressing dependencies between them.

That said maybe you can write Editor class in your Unity package that is InitializeOnLoad and that writes your nuget dependencies into packages.config file if they are not already there and then call AssetDatabase.Refresh to trigger the nuget restore process.

camille-avatarmedical commented 2 months ago

Thanks for the very interesting feedback @igor84. Would you mind sharing details about how you split your code into nuget packages? Notably:

igor84 commented 2 months ago
marked-one commented 2 months ago

When I stumbled upon this problem, my initial guess was exactly what @igor84 proposes in his first comment. But the code in the package itself can't execute in case of errors. And this is exactly the case when no dependencies are present. It is possible to put code under Version Defines for your own packages, but they can only be added for Unity Editor, Unity modules and UPM packages. So this doesn't cover the case with NuGet packages, or Asset Store assets. Probably a DLL in a package can execute in case of compilation errors, but I didn't go that far.

My second idea was to put a file, e.g. a json, with a list of dependencies in the package. And then implement a tool that parses this file and installs the required dependencies. What I didn't like about this approach is that I first install a package and then I need to resolve dependencies via manually pressing e.g. "Resolve" button. I didn't find a way to automate this, as there's no callback after a package is installed. And when installed package has errors no assembly reload happens either. Plus, I didn't test whether such a tool will work when installed after the package that fails to compile, though I remember I had some similar issues in the past.

My solution was to fully manage dependencies outside of packages. I created an "installer tool", essentially a Scriptable Object with 3 lists (NuGet & UPM packages, and Asset Store assets) and an Install button. Internally there's a bit more complex code than just a Scriptable Object, but this is how "user interface" looks like. It is then possible to create multiple Scriptable Object assets containing different sets of packages and use them as installers. So here I don't deal with the dependencies after I install packages, I instead install the package with all the dependencies. The only drawback I found is that these assets should be shared somehow. In my case I simply put them in the same package with my "installer tool" as I am the only user of it so far.

And yes, in my case I first install NuGet packages, then UPM packages, then Asset Store assets, as dependencies usually go the other way round.

marked-one commented 3 weeks ago

Just in case, I put my tool on GitHub: https://github.com/marked-one/UnityBulkPackageInstaller

sindrijo commented 2 weeks ago

My second idea was to put a file, e.g. a json, with a list of dependencies in the package. And then implement a tool that parses this file and installs the required dependencies. What I didn't like about this approach is that I first install a package and then I need to resolve dependencies via manually pressing e.g. "Resolve" button. I didn't find a way to automate this, as there's no callback after a package is installed. And when installed package has errors no assembly reload happens either. Plus, I didn't test whether such a tool will work when installed after the package that fails to compile, though I remember I had some similar issues in the past. And yes, in my case I first install NuGet packages, then UPM packages, then Asset Store assets, as dependencies usually go the other way round.

Did you try using PackageManager.UI.IPackageManagerExtension?

It has the following members:

You would probably need to have this plugin already installed, as I'm not sure how reliable those callbacks are if the plugin lives in the package being installed itself.

marked-one commented 2 weeks ago

@sindrijo yep, I considered this API.

But it has a serious limitation: it is tied to the Package Manager UI.

This means, it only solves the problem for when you install packages manually.

But whenever a package is installed from code via Client API or via manually changing manifest.json, these callbacks won't trigger unless Package Manager window is open and active.

So, not a universal solution. Though maybe it could be enough to solve the OPs problem.

And yes, your guess is right, the OnPackageAddedOrUpdated callback runs before domain reload, so it can't be triggered when the code is in the installed package itself, as it is not yet compiled.