Skip to content

Instantly share code, notes, and snippets.

@LotteMakesStuff
Last active January 5, 2023 20:54
Show Gist options
  • Save LotteMakesStuff/6e02e0ea303030517a071a1c81eb016e to your computer and use it in GitHub Desktop.
Save LotteMakesStuff/6e02e0ea303030517a071a1c81eb016e to your computer and use it in GitHub Desktop.
UPM: How to make a custom package

UPM: How to make a custom package So, Unity has this shiny new package manager, and you have code you want to share between projects - wouldn't it be great if we could bundle up our shared code and plug it into all the projects that need it? Let's figure out how to make our own Package!


Todo

  • Modify the project manifest
  • Make a package manifest
  • Package the manifest up with some test code
  • Try it out in Unity!

Project Manifest

Unity uses a 'Manifest' file to tell it what packages a project cares about. It's essentially a list of the packages we want and what versions we care about. we can also flag up packages we don't want included. Let's open up our manifest and in a custom dependency on a local package.

Note: where to find the manifest

  • Depending on what beta version of Unity 2018.1 you are using, manifest.json might be in a diffent folder as its location changed in b9
    • Unity 2018.1b9 >: ProjectRoot/Packages
    • Unity 2018.1b1-b8: ProjectRoot/UnityPackageManager
{
"dependencies": {
"com.unity.package-manager-ui": "1.8.0",
"com.unity.analytics": "exclude",
"com.lms.boundingvolumes": "file:../../CustomPackageTest/lmsBoundingVolumes"
}
}

This is an example of what a projects manifest file might look like. It's easy to see we have a dependency on the Package Manager UI (explicitly version 1.8.0). We have also excluded the Analytics package. There could be any number of other packages included or excluded, depending on your projects precise setup and requirements.

More interestingly, we have added in our custom package, com.lms.boundingvolumes. As we can see, all package names start with com. The packages Unity hosts on its repository then all have .unity.. This clearly identifies them as packages published by Unity. For our custom package, I've replaced that with .lms., short for LotteMakesStuff. Finally, we have the name of our actual package! In this example were packing up code that implements a Bounding Sphere structure, so we picked the name boundingvolumes as it nicely reflects the contents of our package. (obviously, our package could contain any code - I just picked bounding volumes as I was working on them recently!).

Unlike with the package we are getting from Unity's package repository, instead of specifying a version number we want UPM to resolve, instead, we are providing a local, relative file path to our package. File locations have to be relative. this might cause issues with code stored in version control, as we have to make sure the packages we depend on are in the same relative position on each development system. In this example, we go back two levels to the folder that contains our projects root folder and then going into a folder containing just our custom package. In a source control context, it might make more sense to host the shared content in a Unity project of its own and then have the package in a subfolder of the host projects Assets folder. this provides an easy way to test and develop our shared components and a nice way to ensure the relative paths work, all a developer has to do is ensure the shared code project is checked out side by side with the project that consumes it.

Todo

  • Modify the project manifest
  • Make a package manifest
  • Package the manifest up with some test code
  • Try it out in Unity!

Package Manifest

The package manifest sits in the root of the folder our packages contents is stored in and provides a whole bunch of metadata to Unity describing what our package actually is. Most of this is currently used by the Package Manager UI to control how it draws our packages information, or by the Package Repository to resolve references to our package. Unfortunately, as we currently cant publish our own packages to the repository - most of it does nothing but it's still useful to make sure its set so it shows in the UI correctly. The tags that Unity currently uses are defined in the package manager documentation

{
"name": "com.lms.boundingvolumes",
"displayName": "Bounding Volumes",
"version": "0.0.1",
"unity": "2018.1",
"description": "Custom Bounding Volume structs, for situations where we cant use the ones provided by Unity.",
"keywords": [
"maths",
"unity"
],
"category": "Unity"
}
  • name - this is the name of the package and has to match the name we use in the project manifest exactly. Its even case sensitive.
  • displayName - The Package Manager UI window will show the value from name by default, which isn't particularly human readable. We can provide a more readable string for it in this tag
  • version - All UPM packages should provide a version, using the Semantic Versioning system by convention. As our packages are only referenced locally and never resolved by the package manager, this is less important but still a best practice.
  • unity - the minimum version of unity this package needs to work, which for now is pretty much always 2018.1
  • description - this is a basic description that is displayed in the Package Manager UI when our package is selected
  • keywords & category - this dont really apply too much to us right now, keyword is used for repository search and category doesn't seem to be used anywhere right now
  • dependencies (not shown) - we can include a list of packages we depend on, in a similar way that the project manifest does.

Todo

  • Modify the project manifest
  • Make a package manifest
  • Package the manifest up with some test code
  • Try it out in Unity!

The Test Package

Lets build up a really simple test package. All it will contain is the Package Manifest we wrote, one small code file, and an assembly definition. Assembly Definition files are a realtivly new unity feature which lets us partition code off into sepearte files when it gets compiled. This will help keep unitys compilation times down, especally when pacakges contain a lot of code. You can read more about them here

This is what our entire looks like.

Todo

  • Modify the project manifest
  • Make a package manifest
  • Package the manifest up with some test code
  • Try it out in Unity!

How does it look in the Package Manager UI?

Todo

  • Modify the project manifest
  • Make a package manifest
  • Package the manifest up with some test code
  • Try it out in Unity!

Notes

  • The package manager seems to be based on NPM. NPM supports URL links to packages and links to packages in git repositories, unfortunately, I've not been able to get these to work with UPM, only local, relative file references.
    • let me know if you get this working!
  • Currently, the Unity Package Manager UI window seems to ignore the author: tag in package manifests, and displays every package as being written by Unity.
  • You can find a Zip with our test Package below! extract it somewhere on your system and set up a relative file dependency just like we did in this tutorial to try it for yourself! you should then be able to use the LotteMakesStuff.Mathmatics.BoundingSphere class in your test project!

Got Questions? Im @LotteMakesStuff on Twitter, My DMs are open!

Buy Me a Coffee at ko-fi.com Become a Patron!

@LotteMakesStuff
Copy link
Author

@andybak git endpoints is on the roadmap the disclosed at unite berlin! yay!
Oh, and my sneaky hack was to implement a proxy server that sat between Unity and UPM. it could echo all the calls to the UPM service and modify any return results i was interested in to inject my own packages. It was fun, but ultimatly didnt work very well

@UCh
Copy link

UCh commented Oct 4, 2018

Apparently is possible to use your own NPM registry with packages, including transitive dependency resolution https://forum.unity.com/threads/other-registries-than-unitys-own-already-work-nice.533691/

@shrikky
Copy link

shrikky commented Dec 19, 2018

Thank you very much! I am getting this error :

error CS0009: Metadata file `C:/Users/xxx/projects/SystemsUnityTools/SystemsUnityTools/Packages/Moq.4.10.1/lib/net45/Moq.dll' does not contain valid metadata

Please help

@keenanwoodall
Copy link

keenanwoodall commented Feb 2, 2019

@LotteMakesStuff What is the best way for a package to get/create files?

Example 1:
If a tool has some scriptable object that stores settings, it shouldn't be stored alongside the tool in the Packages folder because any changes to it will get overridden when the package files are updated/synced with the source files, right?

Example 2:
A package has a custom texture it needs for a custom editor. How can we get this file when the actual package's file path could be many things?


AFAIK, if the package source is on disk, the package is just referenced (not copied over). However if the package is created by Unity (or hosted on a repo), the files are copied under YourProjectName/Library/PackageCache/name@version. And if the package source is a repo, the packages folder name ends up being name@somereallylongcommithash which makes it even harder to predict any file paths.

All of these different variables has prevented me from being able to load assets from within the package. Is there a way to get the package's file path?

[Edit] So it looks like AssetDatabase.FindAssets and AssetDatabase.LoadAssetAtPath will let you load from "Packages/com.example/example" regardless of the package's real location. Makes sense as the package is in the database.

@MoutonSanglant
Copy link

MoutonSanglant commented Feb 13, 2019

Hello, just to inform that git support is possible since 2018.3b.

Note that (quoting okcompute_unity):

As stated in the release notes, this is an experimental feature. We are targeting production ready quality for 2019.1. Super glad that you are trying this out though. Please, let us know if you find any issues.

In order to enable using a git remote, edit your manifest.json like so:

  "dependencies": {
    ...
    "com.mycompany.package": "https://your.remote-git.com/path/to/repository.git",
    ...
}

You can find more information on this topic: https://forum.unity.com/threads/git-support-on-package-manager.573673/

@Morgan-6Freedom
Copy link

Morgan-6Freedom commented Oct 26, 2019

Hello, I succeed to create a package on my github, with the manifest json.
However, how do I add it in my project ? The only option available is "Add Package from disk"

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment