Plugins are tools and assist scripts that are designed to add features to gw2cc and do not take full control of the client, in contrast to bots.
Plugins must be located in the plugins/ folder. The name of the plugin is defined by the name of the folder it resides in. E.g. if you create a folder plugins/my_awesome_plugin your plugin will be displayed in the plugin menu as my_awesome_plugin.
For a hands-on quick start, directly go to Creating a Simple Plugin.
Loading Plugins #
Plugins can either be enabled or disabled as indicated by the checkbox in the plugin menu. If enabled, the PluginManager will try to auto-load the plugin on every scene change.
For this, the PluginManager searches for a [SceneName].tscn file in the plugin directory, where [SceneName] is a placeholder for the name of the current scene (e.g. Ingame.tscn for the main ingame scene). If found, the manager will instantiate the packed scene and append the plugin node to the SceneTree. At the end of a scene, plugin nodes are automatically unloaded again. This, in particular, also happens if you switch maps!
As a consequence of these designs, the correct place to perform initialization is _ready(), while _exit_tree() is the proper place to perform cleanup. Furthermore, plugins need to make sure to save and restore state respectively in these methods if they want it to persist across scene changes. For this purpose, the global Singleton node can come in handy.
Voluntary Unloading #
A plugin can decide at any point to unload itself, for instance because a critical error occurred, or because certain preconditions are missing (e.g. because a character has an incompatible class). Usually this will happen during startup, i.e. during _ready(). To unload oneself, simply call the unload() method of your Plugin object. If you do so, you should always make sure to add a reason via the warning() or error() method beforehand so that the users can understand why a plugin has been unloaded.
func _ready():
Manager.agent.connect("controlled_character_spawned", self, "_on_own_character")
func _on_own_character(cc):
var plugin = PluginManager.plugins["my_plugin"] # gets a reference to our own plugin
if cc.get_profession() != AgentChar.PROFESSION_ELEMENTALIST:
plugin.warning("This plugin is only available for Elementalist characters")
plugin.unload()
return
You should also make use of this option, if your plugin only works in either standalone or attached mode but not in both.
Dependencies #
Plugins can depend on other plugins for functionality, either optionally or necessarily. To do so, developers should use the PluginManager directly to manually load a dependency if needed. In total 3 steps need to be performed for this:
- Check if the required plugin actually exists, i.e. is in the plugins folder.
- If it does, check if it’s already loaded, i.e. instantiated in the scene.
- If not, try to load it. If this step fails; a plugin can decide on its own if it wants to stay loaded or if it wants to unload itself with an error.
All together, this could for instance look like this:
def _ready():
var plugin = PluginManager.plugins["my_plugin"]
var dependency = PluginManager.plugins.get("DPSMeter")
if dependency == null: # Step 1
plugin.critical("This plugin requires the DPSMeter plugin to work. Please visit the gw2cc store to obtain a copy.")
return
if not dependency.loaded and not dep.load(): # Step 2 and 3
plugin.critical("Failed to load the DPSMeter plugin.") # use warning() here instead, if it's only an optional dependency
return
# We can access the loaded dependency via the .node property of the Plugin object:
var dps_meter = dependency.node
dps_meter.foo_bar()
In the future, we plan to add some small convenience functions to the PluginManager that simplifies this process a bit.