Plugin Dependencies
As of 1.21.0, Openplanet plugins can depend on other plugins. For a plugin that depends on another plugin to run, both plugins need to be installed. For example, if plugin A depends on plugin B, then both A and B need to be installed for A to successfully load.
Plugins that depend on other plugins will also inherit a part of the implementation of those plugins. To be more precise, a dependent plugin will import a dependency's exports. These exported functions (and optionally shared classes) can then be used by any dependent plugins to perform actions within the context of the other plugin.
For example, the built-in NadeoServices
plugin allows dependent plugins to use the same access tokens for Nadeo's live services. When multiple plugins are depending on NadeoServices
, only 1 access token will be created inside of the NadeoServices
plugin itself, which the dependent plugins are then making use of. This saves resources, simplifies development because you don't have to worry about authentication, and avoids any potential rate limiting or other conflicts.
Depending on a plugin
If you're a developer and you wish to depend on another plugin, you have to add the plugin dependency to your info.toml
file. For example, if you are integrating with the NadeoServices
plugin, you would add a dependencies
array to your [script]
section:
[script]
dependencies = [ "NadeoServices" ]
In this case, it will depend on the plugin using the identifier
NadeoServices
. The identifier of a plugin is found in several ways, but the quickest is to look at the location of the plugin; it will either be the folder name, or the file base name of a.op
file. For example, the plugin identifierFooBar
could refer toC:/Users/Username/OpenplanetNext/Plugins/FooBar.op
orC:/Users/Username/OpenplanetNext/Plugins/FooBar/
.
When your plugin loads, Export.as
from NadeoServices
is compiled into your plugin as well. This file contains functions that interact with the plugin. It's recommended you check the actual source of this file, as it often contains documentation on how to use a plugin's exported scripts.
For the NadeoServices
dependency example, you'd then simply call any of the exported functions:
void Main()
{
NadeoServices::AddAudience("NadeoLiveServices");
// ...
}
Exporting to other plugins
If you want other plugin developers to be able to have a dependency on your plugin, you have to export script files. There's 2 ways to do this inside of info.toml
. The first is exports
, and the second is shared_exports
.
exports
is an array of files in your plugin that will be compiled into any dependent plugins, but NOT in the dependency plugin.shared_exports
is likeexports
, except it will be compiled into both plugins.
Shared exports are usually only useful if you want to provide classes using Angelscript's shared entities.
[script]
exports = [ "src/Export.as" ]
shared_exports = [ "src/ExportShared.as" ]
Exporting functions
Function exports are using Angelscript's function importing to create a connection between multiple script modules.
This works by exporting a file containing your function definition using the import .. from "..";
syntax. For example, if your plugin ID is Foo
, you could write the following exported script:
namespace Foo
{
import void DoSomething() from "Foo";
}
Note that the exported script is not compiled with your plugin, so you have to declare the actual function in a separate file:
namespace Foo
{
void DoSomething()
{
print("Hello, world!");
}
}
If you've worked with header files in C or C++ before, this concept should be familiar. When you change the function signature, make sure you change it in both files!
Exporting classes and other entities
If you want to export a class (via an exported function's return value or parameter for example), you have 2 ways of doing it.
- Add the class to a regular exported script. The downside about this is that you can't use the same class in your own code since exported scripts are not compiled into the dependency plugin.
- Make the class shared and put it in a shared exported script. This way you can use (and pass around handles to) the class.
To make a class shared, you can simply add the shared
keyword as described in Angelscript's shared entities page. Keep the following important rule in mind though:
Shared entities have a restriction in that they cannot access non-shared entities because the non-shared entities are exclusive to the script module in which they were compiled.
If you feel like breaking this restriction, consider whether a class really needs to be exported. It's likely you can solve the problem without any shared entities, purely with exported functions.
Required and optional dependencies
By default, the dependencies you list in dependencies
are required dependencies. That means that your plugin won't compile if any of the dependencies are not installed, and will throw an error at the user.
As of Openplanet 1.22.2, you can also specifiy optional dependencies by using optional_dependencies
. This is an additional array of plugin ID's to optionally depend on. If such a plugin is not installed, then your plugin will still compile, but without any of the exported files.
If an optional dependency is installed however, it will add a preprocessor definition that you can use in your scripts. The definition will have a prefix of DEPENDENCY_
followed by the plugin ID in uppercase, with spaces, dashes, and periods replaced by underscores. For example, if you have an optional dependency on Dashboard
and Dashboard is installed, you can check for DEPENDENCY_DASHBOARD
in your scripts:
#if DEPENDENCY_DASHBOARD
auto playerState = Dashboard::ViewingPlayerState();
// ...
#else
warn("Dashboard is not installed!");
#endif