MCDR Plugin
What is a MCDR plugin
A MCDR plugin is a single .py or .mcdr file or a directory with specific file structure located in plugin directories.
See Plugin Format document for more information about plugin format
The list of the plugin directory can be defined inside the configuration file. At start up, MCDR will automatically load every plugin inside every plugin directory
Check the example plugin repository or the plugin template repository for more references
Quick Start
Open one of the plugin directories of MCDR, create a file named HelloWorld.py
cd my_plugin_folder
touch HelloWorld.py
open it and enter these code
PLUGIN_METADATA = {
'id': 'hello_world',
'version': '1.0.0',
'name': 'My Hello World Plugin'
}
def on_load(server, old):
server.logger.info('Hello world!')
Return to MCDR console, enter !!MCDR reload plugin, and you should see the hello world message from your plugin
[TaskExecutor/INFO] [hello_world]: Hello world!
Great, you have successfully created your first plugin
Metadata
The meta data field provides the basic information of the plugin. It’s declared as a json object contains several key-value, e.g.:
{
"id": "example_plugin",
"version": "1.0.0",
"name": "Example Plugin",
"description": "Example plugin for MCDR",
"author": "Fallen_Breath",
"link": "https://github.com/MCDReforged/MCDReforged-ExamplePlugin",
"dependencies": {
"mcdreforged": ">=2.0.0-alpha.1"
}
}
Different plugin format has different ways to declare its metadata, but the contents of metadata are the same
See also
Metadata document
Entrypoint
Entrypoint is a module specifying what module MCDR will import when loading your plugin. It’s the bridge between your plugin and MCDR
For Solo Plugin the entry point is the plugin itself.
For Multi file Plugin the entrypoint is declared in metadata,
with default value the id of the plugin, which is the __init__.py file in the folder named plugin id
For example:
MyPlugin.mcdr
my_plugin/
__init__.py
source.py
mcdreforged.plugin.json
For this multi file plugin, with default entrypoint value, MCDR will import the module my_plugin,
which will actually loads the __init__.py in my_plugin/ folder inside the MyPlugin.mcdr file.
on_load function inside the __init__.py will be registered as an event listener
If the entrypoint is set to my_plugin.source, then MCDR will import my_plugin.source, which will actually loads source.py in my_plugin/ folder
The entrypoint module instance is also used in get_plugin_instance().
The entrypoint module instance is also what the second parameter in Plugin Loaded event is
Plugin Registry
Plugin registry is a collection of things that plugin registered for. It will get cleaned up every time before the plugin gets loaded, so you’d better register them in Plugin Loaded event
Event listeners
There are 3 methods to register an event listener for you plugin
Declare a function inside the global slope in the Entrypoint module with the specific name. It’s the legacy registering method to register a listener and it only works with events provided by MCDR. Check Default Event Listener for more detail
For example, the widely-used function below is a default Plugin Loaded event listener
def on_load(server, prev): do_something()
Manually invoke
register_event_listener()method to register an event listener. You can specify the callable object and the priority for the event listenerHere some examples about manually register event listeners
def my_on_mcdr_general_info(server, info): pass def on_my_task_done(server, my_task_info, my_task_data): # the 2nd and 3rd parameter is determined by the plugin that emits this event pass def on_load(server, prev): server.register_event_listener('mcdr.general_info', my_on_mcdr_general_info, priority=500) server.register_event_listener(MCDRPluginEvents.PLUGIN_UNLOADED, my_on_unload, priority=2000) server.register_event_listener('myplugin.task_done', on_my_task_done)
Use
event_listener()decorator
(Beta feature) Since v2.14, you can use an async function as the event listener callback function
async def on_load(server, prev):
await do_something_with_async()
Command
Rather than manually parsing info.content inside user info event callback like on_user_info,
MCDR provides a command system for plugins to register their commands
Check the Command Tree document for more detail about building a command tree
Assuming that you have already built a command tree with root literal node root, then you can use
the register_command() method to register your command tree in MCDR
server.register_command(root_node)
Help message
Plugin can register its help message with register_help_message() to MCDR,
so that users can use !!help command to view the help messages of all commands
Translation
If your plugin needs to handle some message localization or translation things, you can let MCDR help you:
register a translation via register_translation() method
and use tr() or rtr() to get the translated string
See the Translation section in Some tips to plugin development for some suggestions about using translation
Import a plugin
During multi file plugin loading, MCDR will append the path of the multi file plugin to sys.path.
For packed plugin, it’s path of the .mcdr file; For directory plugin, it’s the path of the directory
Therefore, you can simply import other plugin by importing its plugin id using the import statement.
It’s also the recommended way to do that since it provides code hints and more information for your IDE
Apart from this, you can also use get_plugin_instance() method
to import the entry point of the plugin,and this is also the only way to import a solo plugin.
For multi file plugin the result is the same as directly importing the plugin
import my_lib_plugin as libA
libB = server.get_plugin_instance('my_lib_plugin')
print(libA == libB) # True
Don’t forget to declare plugin dependency in your metadata, or MCDR will not guarantee a correct plugin loading order