MCSC 全程 MinecraftServerController,为一款基于 Python 开发的服务端服务端管理系统,它的核心特色是支持 Python 开发的插件,并且可以热加载服务器插件,能优化并丰富玩家在原版(vanilla)服务端的游戏体验。
目前正处于开发阶段,功能规划如下:
功能划分
MCSC 是一款基于
Popen
的信息交互系统,通过与 Minecraft 真实后端的信息输入输出流交互来实现本系统与 Minecraft 的交互功能。MCSC 后端以及 Minecraft 客户端均为通过输入文字对本系统进行交互操作。控制权限:限定不同玩家通过客户端对本系统的不同权限,确保系统安全性。通过服务器端控制台的所有操作为最高权限。在默认配置中,owner 以及 admin 权限可以对服务器进行敏感操作管理;helper 可以进行部分敏感操作;user 以上可以执行插件;vistor 玩家没有任何权限。
在服务器端进入后台时,将展示交互式后台,采取类似 Linux 下的
auto-suggestion
的方法为后端提供指令补全及建议。MC 客户端为正常的信息输入,不能补全。通过统一 API 接口的方式,为不同 Minecraft 的服务端提供兼容,例如 waterfall / forge / bukkit / CatServer / Velocity 等众多第三方服务端。
拓展插件形式,包括但不仅限于单 Python 文件插件 / 处于文件夹的多文件插件 / 通过本系统打包的 .mcsc 多文件打包插件
插件事件
插件事件是插件与控制台和服务器交互的重要方式。
当服务器触发某一事件时,MCSC 会以处触发的参数传递至注册该事件的监听器,然后调用该监听器的回调函数。事件监听器默认以最高优先级运行,可以在插件中自定义事件监听的优先级
生命周期
一些 MCSC 的事件可以被划分成三个生命周期
- 插件生命周期:插件被加载 -> 插件被卸载
- 服务端生命周期:服务端启动 -> 服务端启动完成 -> 服务端被终止 -> 服务端完成终止
- MCSC 生命周期: MCSC 启动 -> MCSC 终止
插件被加载
插件被加载事件将在插件加载后被触发一次,若你需要注册一些事件监听器/命令/帮助消息,以及初始化参数,那么你应该将它们置于这个函数里。
def on_load(server: PluginServerInterface, prev_module): |
由于它是插件生命周期中的第一个事件,因此只能使用默认事件侦听器注册该事件,因此 on_load
函数是插件的入口点。因此,不应该在 on_load
函数中分发自定义事件,否则它将无效。MCSC 的事件侦听器存储此时尚未初始化。
- Event ID: mcsc.plugin_loaded
- Callback: PluginServerInterface, prev_module
- Default function: on_load
插件被卸载
当 MCSC 卸载插件实例时,将派发该事件。这可能是由插件重载或卸载引起的。除此之外,在 MCSC 关闭过程中,该事件也将被派发,因此这非常适合用于执行清理操作。
- Event ID: mcsc.plugin_unloaded
- Callback: PluginServerInterface
- Default function: on_unload
标准信息流
服务器输出新一行文本,或者从控制台中输入文本时,触发此事件。 MCSC 将把文本解析为 Info 对象。在这种情况下,插件可以响应信息。
$ e.g: |
- Event ID: mcsc.general_info
- Callback: PluginServerInterface, Info
- Default function: on_info
用户信息
用户信息 事件与 标准信息 事件非常相似,但仅在用户发送信息时——更准确地说,info.is_user
为 True
时——才会触发。如果你需要一种简单的方式来处理用户输入,则可以使用此事件。以下是一个示例用法:
def on_user_info(server: PluginServerInterface, info: Info): |
- Event ID: mcsc.user_info
- Callback: PluginServerInterface, Info
- Default function: on_user_info
玩家离开
一名玩家离开了游戏。插件可以清理与玩家相关的对象。
- Event ID: mcsc.player_left
- Callback: PluginServerInterface, player_name
- Default function: on_player_left
自定义事件
除了 MCSC 本身,插件还可以分发自己的事件。你需要做的就是调用带有事件和一些参数的 server.dispatch_event API。
自定义事件是在插件之间传递消息的好办法。这也是一种不错的间接让插件响应其他插件请求的方式。
MCSC 指令树
本系统默认提供了参数拆分、解析处理,方便判断参数执行条件,如果 Mojang 的 Brigadier
工作流程
MCSC 维护了一个 dict 用于储存注册的指令。该 dict 的值均为指令树根节点列表,而值对应的键则是根节点的字面值。有了它,MCSC 可以快速地找到可能可以接收到来指令的指令树。
每次处理用户信息时,MCSC都会尝试将用户输入解析为指令。它将用户输入的第一个分段作为键来查询指令树存储字典。如果指令存在,则调用 info.cancel_send_to_server()
来阻止将信息发送到服务器的标准输入流 ,然后使用对应的指令树来处理该指令。
如果解析指令时发生错误,且插件未将错误设置为已处理,则 MCSC 会将翻译后的指令错误消息发送到指令源。
构建指令树
假设插件 example.py 包含三种指令:
!!example_plg list
!!example_plg remove <id>
!!example_plg add <player> <message>
要实现这些指令,我们可以构建如下所示的指令树:
Literal('!!email') |
因此,当执行 !!example_plg remove 1
时,将发生以下过程:
- 于节点
Literal('!!email')
解析指令!!email remove 1
。- 字面量节点
Literal('!!email')
获取了!!email remove 1
的第一个元素,它是!!email
——与字面量节点匹配。 - 现在余下的指令是
remove 1
。 - 于是,它搜索其字面量子节点,找到与下一个指令元素
remove
匹配的子节点Literal('remove')
。 - 这样,它让该子节点处理其余指令。
- 字面量节点
- 于节点
Literal('remove')
解析指令remove 1
。- 字面量节点
Literal('remove')
获取了remove 1
的第一个元素,它是remove
——与字面量节点匹配。 - 现在余下的指令是
1
。 - 然后它搜索其字面量子节点,但未找到与下一个指令元素
1
匹配的任何字面量子节点。 - 因此,它让它的非字面量子节点 Integer(‘id’) 处理剩余指令。
- 字面量节点
- 于节点
Integer('id')
解析指令1
。- 整数节点
Integer('id')
获得了1
的第一个元素,这是一个合法的整数。 - 它使用键
id
将值1
存储到上下文 dict 中。 - 然后,它发现指令解析已经完成,因此它以指令源和上下文 dict 作为参数来调用回调函数。
- 整数节点
- 至此,指令解析完成。
匹配文字节点,解析剩余指令,将解析后的值存储在上下文字典中,这就是指令系统的工作方式。
上下文
上下文(Context)储存着当前指令解析过程中的信息,是一个继承自 dict 的类
指令解析过程中解析得到的值将会使用 dict 的方法,储存在上下文中。这意味着你可以使用 context['arg_name']
来访问这些值
指令节点
- TODO
参数节点
- TODO
API
当你需要从 MCSC 中导入些东西时,除了直接从 MCSC 的内部实现中导入外,你还可以从 MCServerController.api 中进行导入。
MCServerController.api 是供插件开发者导入的包。如果你仅从 api 包进行导入目标类,就可以保证插件导入目标类的导入路径与目标类的实际路径解耦。如果以后 MCSC 重构了目标类,亦或是移动了目标类的位置,那么仅从 api 包中导入目标类的插件就能丝毫不受影响。
WatchDog
看门狗是一个监视着任务执行者 (task executor) 线程运行的守护线程。
所有 MCSC 相关的事件,都会在任务执行者线程中作为任务,按顺序依次派发及执行。当一个任务在任务执行者线程中运行了超过 10 秒,看门狗将会认为任务执行者被阻塞了,并将为 MCSC 重新创建一个任务执行者线程,因此设计不良的插件不会永远地阻塞 MCSC 的运行逻辑。
如果你想要在你的插件中运行一些耗时的工作,推荐创建一个线程并使其在新线程中执行。@new_thread 装饰器提供了一种简单的方法来做到这一点。
命令行接口
MCSC 提供了一些实用的命令行接口(CLI)工具。如果你在启动 MCSC 的时候在启动指令末尾追加一些参数。使用方法:在启动 MCSC 的命令末尾追加一些参数。
以下命令来显示 CLI 的帮助信息:
python -m mcdreforged -h |
CLI 命令的格式为:
mcdreforged [global args] <sub_command> [sub_command args] |
全局参数
-q
,--quiet
: 禁用 CLI 信息输出
子命令
start
python -m mcdreforged start [-h] |
同 python -m mcservercontroller
一样,启动 MCSC
init
python -m mcdreforged init [-h] |
准备 MCDR 的工作环境
在当前工作目录下生成默认配置、权限文件,及常用的文件夹,包含:
- logs/
- configs/
- plugins/
- server/
- config.yml
- permission.yml
More args to be added
Wait and see.
Author: DioPong
Permalink: https://blog.2to.fun/post/notebook/MinecraftServerController/
文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。