Server Handler

Server handler is the object which parses server output and provides command interfaces to control the server

MCDR itself has already includes a number of server handlers for widely-used Minecraft related servers, but in case you have a server with custom output format, you can write you own server handler, and assign MCDR to use it.

To design a server handler, you need to inherit from an existed server handler class, or the base class AbstractMinecraftHandler

It’s recommend to firstly have a look at the implementation of the server handlers in MCDR first and try to understand them

For easier usage, management and possible distribution in the future, it is recommended to provide server handlers by creating a MCDR Plugin and using the register_server_handler() API

Example

In this example, we have a vanilla server, but some of the players have a prefix on their username, which result in some changes to the message format of the player chat message. For Example, A player with id Steve and prefix [Builder] might have following chat messages:

<[Builder]Steve> Hello
<[Builder]Steve> !!MCDR status

For the default vanilla handler, [Builder]Steve is an illegal player name. Luckily all possible prefixes of the players in the server follows the same format [Prefix]PlayerName. So it’s possible to make a dedicated handler for the server

For example, we create a MCDR plugin and write the following codes as its entrypoint, which creates and registers a handler to handle player names in this server correctly

import re

from mcdreforged.handler.impl import VanillaHandler


class MyHandler(VanillaHandler):
    def get_name(self) -> str:
        return 'the_handler_for_my_server'

    def parse_server_stdout(self, text: str):
        info = super().parse_server_stdout(text)
        if info.player is None:
            m = re.fullmatch(r'<\[\w+](?P<name>[^>]+)> (?P<message>.*)', info.content)
            if m is not None and self._verify_player_name(m['name']):
                info.player, info.content = m['name'], m['message']
        return info


def on_load(server, prev_module):
    server.register_server_handler(MyHandler())

Then you can start using the handler by loading or reloading the plugin that you’ve just created

Quick guide: Create a working solo plugin providing your custom handler

The easiest way to create a plugin is to create a Solo Plugin, which consists of a single .py file

  1. Assuming the plugin_directories config contains the plugins/ directory, you can create a new solo plugin by creating and editing the file plugins/handler_for_my_server.py

    import re
    
    from mcdreforged.handler.impl import VanillaHandler
    
    PLUGIN_METADATA = {
        'id': 'handler_for_my_server',
        'version': '0.0.0',
    }
    
    class MyHandler(VanillaHandler):
        def get_name(self) -> str:
            return 'the_handler_for_my_server'
    
        def parse_server_stdout(self, text: str):
            info = super().parse_server_stdout(text)
            if info.player is None:
                m = re.fullmatch(r'<\[\w+](?P<name>[^>]+)> (?P<message>.*)', info.content)
                if m is not None and self._verify_player_name(m['name']):
                    info.player, info.content = m['name'], m['message']
            return info
    
    
    def on_load(server, prev_module):
        server.register_server_handler(MyHandler())
    

    Notes that the only difference between the following code and code above, is that it contains a PLUGIN_METADATA field in the global scope as its plugin metadata

    See also

    Metadata document

  2. Load your newly created plugin with command !!MCDR plugin load handler_for_my_server.py

  3. Now your custom server handler should be loaded. Test if it works as expected

  4. (Optional) If it doesn’t, edit the .py plugin file to suit your needs

  5. (Optional) Reload the plugin with command !!MCDR plugin reload handler_for_my_server


As a alternative but not recommended way, you may provide your handler by a single .py file, rather than a plugin

Put the same code as above, without the on_load method, into a .py file, my_handler.py for example, then use it as follows:

  1. Place it into a valid python package in the working directory of MCDR, e.g.:

        my_mcdr_server/
    ++  ├─ handlers/
    ++  │   ├─ __init__.py
    ++  │   └─ my_handler.py
         ├─ server/
        ├─ config.yml
        └─ permission.yml
    

    This make your handler class accessible with from handlers.my_handler import MyHandler

  2. Add the path to the custom_handlers option, then set the handler option to what method get_name() of the handler returns, e.g.:

    handler: the_handler_for_my_server
    
    custom_handlers:
    - handlers.my_handler.MyHandler