MSL-如何编写插件?
2026-07-26
Understand - 理解msl
可以将MSL视为一个盯着服务器后台的管理员,这个管理员能够在极短的时间内响应一切日志信息。
举个例子
① 某天的11点45分14秒,玩家Notch加入了游戏,此时原版的mc后台应该会显示一个:
[11:45:14 INFO]: player Notch joined the game
② 此时MSL——这个迅捷的管理员立即提取信息
- 什么事件: 这个日志的格式符合[HH:MM:SS INFO]: player XXXX joined the game,即玩家进入服务器
- 什么时间: 这个日志中HH:MM:SS对应的时间是11点45分14秒
- 什么玩家: 这个玩家是XXXX
③ MSL——这个管理员立即通知他的所有插件
// 一个插件示例如下
plugin_onEvent('playerJoin', (time, player) => {
setTimeout(() => {
plugin_executeCommand(`tellraw ${player} "欢迎进入服务器"`);
}, 500) // 此处等待500秒是避免mc反应比msl慢
})
这个插件立即通知msl,让msl执行一条tellraw指令,告知该玩家:欢迎进入服务器。
Event - 事件机制
MSL中依靠事件机制来被动的处理各种事情,MSL中事件机制分为两大种:
- 原生事件:MC服务器输出日志(serverLog)、MC服务器启动(serverStart)、MC服务器停止(serverStop)、MC服务器加载完毕(serverDone,触发在mc发出Done!日志时触发)、玩家加入MC服务器(serverJoin)、玩家退出MC服务器(serverQuit)、玩家发送消息(playerSendMessage)、玩家发送指令(playerSendCommand)、MSL插件加载(pluginLoaded)
- 广播事件(请见下文非原生事件):plugin_triggerEvent(event, ...args)所引发的事件
Dependence - 插件依赖
有时我们会有多个插件共同工作,其中有很多插件需要用到相同的逻辑和代码,重新编写未免浪费时间。因此,有很多插件需要依赖一定的前置插件才能运行,这就涉及了MSL中的广播事件以及公共池(pool)
广播事件
广播事件也属于事件(event)的一种,这种事件有一定的特性:
- 与MC服务器无关,只在MSL中广播
- 没有事件注册机制和事件消除机制,这意味着一个事件不需要被创建,但是可以直接通过plugin_triggerEvent方法来触发这个事件
例如:
// pluginA.js
plugin_triggerEvent("pluginLoaded", (pluginName) => {
if (pluginName == "pluginB") {
plugin_triggerEvent("helloPluginB", "pluginA")
}
})
// pluginB.js
plugin_onEvent("helloPluginB", (text)=>{
console.log("Hi, " + text);
})
公共池
一个MSL实例都具备一个公共池(pool),MSL的任何插件都可以访问、修改该公共池。使用公共池的原因一般是某插件需要访问另一个插件的数据,例如一个定时消息插件需要判断玩家是否有权限创建消息,就需要读取权限节点插件的数据。
为什么不使用广播事件?通过广播事件创建数据,需要不断的触发事件并注册响应事件,并且还可能需要销毁响应事件。
node_modules
一些实在与玩法没有关联的插件或许不应该放在plugins文件夹里?自1.3.0之后,msl将自动加载node_modules中以msl-开头文件夹的autoload.js文件,并提供MSL实例以及一些实用工具。
Why - 为什么使用MSL
目前也有类似的工具(例如MCDR,使用python编写),但使用MSL开发也有优点,例如:
- 依托于node.js / bun的优秀性能(远远大于Python,在处理长、多日志时更具有优势)
- node.js中有大量便利的npm包(尤其是有关minecraft方面的),他们在使用时往往比python付出更少的代码
- MSL本身不依靠任何的node_modules(即使一些插件需要用到node_modules),直接从github上下载源码.zip即可,这样安装和使用都便捷
- 编写方便,虽说py也编写方便,但是msl直接提供了随版本更新的README中英对照版以及CLAUDE.md(适用于所有AI IDE)文件