-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
54 changed files
with
1,781 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Plugin Development | ||
|
||
## Introduction | ||
|
||
In order to develop a NugetForUnity Plugin you need to start with these steps: | ||
|
||
1. Decide on your plugin name. It could just be your company's name for example. | ||
2. You plugin project name should be <PluginName>.NugetForUnityPlugin since the plugin loader will look for dlls which contain NugetForUnityPlugin in its name. | ||
3. If you are targeting Unity older than 2021.3 create a .netstandard2.0 C# library project. | ||
4. If you are targeting Unity 2021.3 or newer create a .netstandard2.1 C# library project. | ||
5. NugetForUnity contains NugetForUnity.PluginAPI.dll that you need to add as a reference in your project. You can copy it to your project or reference using a relative path from some other place. | ||
6. Depending on the needs of your plugin you might also need to add references to UnityEngine.dll and UnityEditor.dll from your Unity installation. | ||
7. Write a class that implements `INugetPlugin` interface. In the `Register` method you will get a `INugetPluginRegistry` that has methods you can use to register your classes that implement custom handling of certain functionalities like installing and uninstalling the packages. | ||
|
||
Note that `INugetPluginRegistry` provides you a few things you can use in your plugin: | ||
|
||
- `IsRunningInUnity` property will be true if the plugin is being run from Unity and false if it is run from command line. | ||
- `PluginService` property that you can pass to your custom handlers if they need to use any of these: | ||
- `ProjectAssetsDir` property that gives you the absolute path to the project's Assets directory. | ||
- `LogError`, `LogErrorFormat` and `LogVerbose` methods that you can use for logging. You should not use `UnityEngine.Debug.Log` methods since they will not work if plugin is used from command line. | ||
|
||
## Extension points | ||
|
||
NugetForUnity implements a certain extension points that your plugin can register to in order to provide custom processing. It can add new extension points in the future without breaking backward compatibility with existing ones. | ||
|
||
### Custom action buttons in Nuget window | ||
|
||
If you want to provide a custom action button next to some packages in NugetForUnity Manage Packages window you can write a class that implements `IPackageButtonsHandler` interface. It will give you a method bellow that you need to implement: | ||
|
||
```cs | ||
void DrawButtons(INugetPackage package, INugetPackage? installedPackage, bool existsInUnity); | ||
``` | ||
|
||
Inside this method you will get info about an online `package` that is being rendered. The `installedPackage` is that same info about the version of that package that is installed if it is installed. It will be null if the package is not currently installed in the project. The third parameter tells you if this package is actually included in Unity itself which means installing it should be disabled. | ||
|
||
Inside the method you can use `GUILayout.Button` Unity method to render additional buttons that will be rendered to the left of current Install/Uninstall/Update and similar buttons. | ||
|
||
Since code here will use UnityEditor functionality which is not available when NugetForUnity is run from command line you should only register this class in plugin registry if it ruinning from Unity. You can do so in your `INugetPlugin.Register` implementation like this: | ||
|
||
```cs | ||
if (registry.IsRunningInUnity) | ||
{ | ||
var myButtonHandler = new MyButtonHandler(registry.PluginService); | ||
registry.RegisterPackageButtonDrawer(linkUnlinkSourceButton); | ||
} | ||
``` | ||
|
||
### Custom package installation | ||
|
||
If you want to customize how packages are installed or just how certain files from packages are extracted and handled you can write a class that implements `IPackageInstallFileHandler` interface. It declares this method: | ||
|
||
```cs | ||
bool HandleFileExtraction(INugetPackage package, ZipArchiveEntry entry, string extractDirectory);` | ||
``` | ||
|
||
When you implement that method you can choose if you want to handle each specific entry from nupkg file and how. If you handle the entry your self and you do not want the default installation of that file to occur you should return true from this method indicating that you have done all the processing you need for this entry. If you still want default installation logic to handle this entry just return false from this method. | ||
|
||
### Custom handling of uninstallation | ||
|
||
If you implement custom handling of installation you will often also need to implement custom handling of uninstallation. For that you need to write a class that implements `IPackageUninstallHandler` interface. It declares two methods: | ||
|
||
```cs | ||
void HandleUninstall(INugetPackage package, PackageUninstallReason uninstallReason); | ||
void HandleUninstalledAll(); | ||
``` | ||
|
||
The first method is called for each package that is being uninstalled. The `uninstallReason` can be: | ||
|
||
- `IndividualUninstall` when individual package uninstallation has be requested by the user. | ||
- `UninstallAll` when user requested all packages from the project to be uninstalled. | ||
- `IndividualUpdate` when user requested a package to be updated so we are uninstalling the current version. | ||
- `UpdateAll` when user requested all packages to be updated so we are uninstalling old versions. | ||
|
||
The second method, `HandleUninstalledAll()` will only be called if user requested all packages to be unininstalled after all the default uninstall processing has been done. If you don't need to do anything special in this case you can leave this method empty. | ||
|
||
## New extension points | ||
|
||
In case you have an idea for a plugin that requires some new extension points please open an issue requesting it with a description of how are you planing to use it. Pull requests implementing new extension points are also welcome as long as a clear description for their need is given. | ||
|
||
# Plugin support implementation details | ||
|
||
This section explains how plugin support is implemented in NugetForUnity which should also explain how new extension points can be added. | ||
|
||
Under src/NugetForUnity.CreateDll there is a NuGetForUnity.CreateDll.sln solution. That solution contains two projects: NugetForUnity.CreateDll itself and NugetForUnity.PluginAPI project. PluginAPI project defines all the interfaces that should be visible to plugin implementations. NugetForUnity project references this one since it also implements and extends some of these interfaces. | ||
|
||
PluginAPI project is setup so that it copies the built NugetForUnity.PluginAPI.dll to src/NuGetForUnity/Editor/ folder where the rest of actual source files of NugetForUnity reside. This is needed because src/NugetForUnity folder contains package.json file identifying that folder as a Unity package that can be locally referenced from the file system. | ||
|
||
CreateDll project has two classes under PluginSupport folder: | ||
|
||
- `NugetPluginSupport` which implements the `INugetPluginService` | ||
- `PluginRegistry` that implements `INugetPluginRegistry` and also has `InitPlugins` method that is called after Nuget.config is loaded and a list of enabled plugins is read from it. | ||
|
||
Note that `AssemblyLoader` class it uses to load the plugins has a different implementation in NugetForUnity.Cli project which is for running from command line. It also has a different implementation of `SessionStorage` class that will return "false" for `IsRunningInUnity` key. | ||
|
||
`NugetPreferences` constructor has code that looks for all plugins installed in the project by checking all assemblies whose name contains "NugetForUnityPlugin" in its name. It will list these plugins in the preferences window so each can be enables or disabled. | ||
|
||
In order to find where are extension points executed in the code you can just search for `PluginRegistry.Instance` through the entire solution. For example you will find that `PluginRegistry.Instance.HandleFileExtraction(...)` is called in `NugetPackageInstaller.Install()` method within the loop that handles the entries for nupgk file that is being installed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#nullable enable | ||
using System.Reflection; | ||
using NuGetForUnity.Cli; | ||
using NugetForUnity.Configuration; | ||
|
||
namespace NugetForUnity.Helper | ||
{ | ||
/// <summary> | ||
/// Assembly load implementation for CLI version. There is another implementation for Unity Editor version. | ||
/// </summary> | ||
internal static class AssemblyLoader | ||
{ | ||
/// <summary> | ||
/// Loads the assembly for the given pluginId | ||
/// </summary> | ||
/// <param name="pluginId">Plugin Id to load.</param> | ||
/// <returns>Assembly of the loaded plugin.</returns> | ||
internal static Assembly Load(NugetForUnityPluginId pluginId) | ||
{ | ||
var loadContext = new NugetAssemblyLoadContext(pluginId.Path); | ||
var assembly = loadContext.LoadFromAssemblyPath(pluginId.Path); | ||
return assembly; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System.Reflection; | ||
using System.Runtime.Loader; | ||
|
||
namespace NuGetForUnity.Cli | ||
{ | ||
/// <summary> | ||
/// Class for loading an assembly. | ||
/// </summary> | ||
internal sealed class NugetAssemblyLoadContext : AssemblyLoadContext | ||
{ | ||
private readonly AssemblyDependencyResolver resolver; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="NugetAssemblyLoadContext"/> class. | ||
/// </summary> | ||
/// <param name="pluginPath">Path to the plugin that will be loaded.</param> | ||
internal NugetAssemblyLoadContext(string pluginPath) | ||
{ | ||
resolver = new AssemblyDependencyResolver(pluginPath); | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override Assembly Load(AssemblyName assemblyName) | ||
{ | ||
var assemblyPath = resolver.ResolveAssemblyToPath(assemblyName); | ||
return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
src/NuGetForUnity.CreateDll/NuGetForUnity.CreateDll.sln.DotSettings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nupkg/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> |
Binary file added
BIN
+7 KB
src/NuGetForUnity.CreateDll/NuGetForUnity/Editor/NugetForUnity.PluginAPI.dll
Binary file not shown.
Oops, something went wrong.