-
Notifications
You must be signed in to change notification settings - Fork 2
The plugin loading process
Plugin loading commences just before the game is loaded. This article describes the different stages of plugin loading.
Locating plugins is done using the reflections library. The client's classloader is paired with a PluginClassLoader that includes all folders and JAR files in user.home\Wingman\plugins. The library then helps with constructing a set of all classes annotated with the Plugin class.
It takes the plugin classes and wraps them using the PluginContainer class. This class tries to locate the PluginDependency/PluginDependencies, Plugin.Setup, Plugin.Activate, Plugin.Deactivate, Plugin.Refresh and Plugin.Helper annotations, setting the PluginContainer's fields to whatever the annotations are annotated to.
Here it also makes sure that you don't load a plugin that you've already loaded. It determines if you've done this by keeping a set of IDs of previously loaded plugins. This means that plugin makers should take care of having a very unique plugin ID for their plugin. This can be done by appending a string of random characters to it.
Since you might want your plugin to depend on another plugin, there is plugin dependency functionality. To specify that you want to depend on for example the newest version of the Developer Utilities plugin:
@PluginDependency(
id = "DevUtils-defaultplugins",
version = ">=0.0.1"
)The dependency parser will then make sure that a user has a plugin with the ID DevUtils-defaultplugins of atleast version 0.0.1. An exception will be thrown if the user's DevUtils plugin is outdated, or if it's simply missing. Plugin versions are based on Semantic Versioning.
After this, plugins are sorted topologically, as to load dependencies before dependants.
At this stage, the method annotated with Plugin.Setup is called for plugins that have it defined. Since the plugin loading is done before the game is loaded, you would want to place any code that will need to be executed before the game launches within the Plugin.Setup method. Please be clever about what code you include in this step, since this is where the user is waiting for the game to boot up.
Here, it iterates over all event classes that have atleast one callback attached to them. It gets the static eventListenerList field of the event classes, and calls bake() on them. "Baking" the event listeners puts all registered listeners for that event from a Set over to an array, since an array is quicker to iterate over than a Set.
The game starts loading at this stage, and after it has been loaded the plugin activation phase starts. A new thread is spawned that invokes the Plugin.Activate method of the plugins that have defined it. This is where your more heavy plugin execution code should be placed, or simply put, any code that isn't dependant on being run before the game has started.
Please join our Slack if you notice anything wrong or would like to contribute to the wiki.
- General
- Installing a plugin
- The plugin loading process
- Development
- Setting up your workspace
- Creating a Gradle project
- Plugin Development
- Creating your first plugin
- Using event listeners