Managing Custom Packages in Unity

Yadi Yasheng
3 min readNov 4, 2021

— finally less of a pain in the ass

Photo by Claudio Schwarz on Unsplash

Context:

Over the years, we all have our systems, framework, libraries, utility scripts that we built up or managed to salvage from the countless side projects that didn’t go anywhere.

Trying to reuse these code in a modular and clean way, had always been a pain in the ass, even with the addition of package manager a few years back.

Devs had to come up with all kinds of janky ways to manage their custom packages.

  1. manually maintain and import stuff, real ghetto
  2. openUPM, or run your own registry to support private packages
  3. integrate packages via git submodule

What I want:

  1. packages are version controlled
  2. clean, easy integration workflow
  3. *when using the package, if I think of improvements or encounter a bug, I want to be able to make changes in place or easily patch it and release it.

Git submodule was the “best” option for me at the time.

// i'd pull in my packages as so
[submodule "Assets/Plugins/Console"]
path = Assets/Plugins/Console
url = https://dylanyasen@github.com/DylanYasen/unity-console.git
[submodule "Assets/Plugins/DataTemplateSystem"]
path = Assets/Plugins/DataTemplateSystem
url = https://github.com/DylanYasen/unity-data-template-system.git

Later at some point, UPM added support for git as direct package endpoint:

"dependencies": {"com.iw.data-template-sytem":     "https://github.com/DylanYasen/unity-data-template-system.git","com.iw.item-system": "https://github.com/DylanYasen/uItemSystem.git"}

After the addition of git endpoint support, there was less of a need for submodule, but the main problem still existed.

The pain point:

// packages have to follow this layout
<root>
├── package.json
├── Editor
│ ├── [company-name].[package-name].Editor.asmdef
│ └── *.cs
├── Runtime
│ ├── [company-name].[package-name].asmdef
│ └── *.cs

This meant I could not have my packages as individual unity projects which i can easily open up, make changes, test and release.

Had couple of janky options to deal with this:

  1. post process step to release the package part of the project, following the required layout, and release to a separate repo. I can work on the package within the full unity project repo, consumer will need to consume the release repo
  2. instead of initializing the repo at the project root, put it in the package folder only
<root>
├── <PackageRoot> * version control initialized for this folder
├── package.json
├── Editor
│ ├── [company-name].[package-name].Editor.asmdef
│ └── *.cs
├── Runtime
│ ├── [company-name].[package-name].asmdef
│ └── *.cs
├── <non package specific stuff>

None of these were good options. I ain’t got time to maintain a release pipeline for packages. And if go with #2, I lose the ability to easily pull down the package, patch & test in a full project environment.

In the end, I was maintaining my packages as full projects, pulling them to local, and symlinking the release part to other projects…

I don’t remember the other weird shit I did over the years just to deal with this mess, I don’t even want to remember.

Package management is a time sink, but it shouldn’t be

Finally something good

I don’t know when this support was added to UPM, I just saw it yesterday and it made my fucking day. Check this shit out:

"dependencies": {..."com.iw.item-system": "https://github.com/DylanYasen/uItemSystem.git?path=/Assets/ItemSystem"...}// ♥️ => ?path=/Assets/ItemSystem

That’s it, that’s all I wanted, a simple way to specify a subfolder for a package.

Now I can maintain my packages like a sane person, and easily releases and consume just by structuring the package to separate release and non-release targets

<Assets>
├── <AbilitySystem - release target>
├── package.json
├── Editor
│ ├── [company-name].[package-name].Editor.asmdef
│ └── *.cs
├── Runtime
│ ├── [company-name].[package-name].asmdef
│ └── *.cs
├── <non release targets>
├── test bed
├── test assets: particles, sample abilities etc
├── test dependencies not meant for release

to consume id just specify the subfolder

"com.iw.ability-system": "https://github.com/DylanYasen/abilitysystem.git?path=/Assets/AbilitySystem"

No more submodule, no more symlink that messes with CI, no more mental hurdle, simple, dumb, easy, just the way I like it.

I don’t know why it took so long to get to this point, it’s not even a complex requirement. I support iteration, however, I think this was a must-have when git endpoint supported was added.

Anyways, I’m happy we have an option that’s workable moving forward.

References:

--

--