简介
LuaInMinecraftBukkit II 是一个 Minecraft Bukkit 服务端插件, 目的是实现使用 Lua 脚本与 Bukkit 服务器交互.
Lua 是一个小巧的脚本语言, 拥有非常简单的语法, 还有着较为不错的运行速度. 试想一下, 用一个轻巧的, 不需要编译就可以运行的脚本编写Bukkit插件将多么美好. 如果要修改一个地方, 那就修改, 然后重新加载脚本就好了, 简直就像梦一样.
与上一代的区别
相比于上一代, 本代更注重于Lua原生虚拟机. 同样的, 本代也基于luajava项目.不过与上一代相比, 本代使用克隆后的luajava仓库. 与原仓库相比, 克隆后的luajava仓库基本上重写了反射部分功能, 能够进一步简化Lua调用Java方法之间的过程, 并且在C语言端提供了非常友好的异常提示.
能做什么?
本插件主要有三大功能:
- 注册指令: 注册你想要的任何指令, 并且自动生成帮助信息和指令层级关系
- 监听事件: 监听任何你想要的Bukkit事件, 即使这个事件是其他插件的自定义事件
- Lua池化: 将 Lua 池化后, 允许提交 Lua 闭包至其他状态机上运行, 以获取真正的多线程并行运行能力: 示例
其他功能有:
- 快速反射: 现在, 为 Lua 的反射组件接入了以 MethodHandle 为基础的快速反射, 相比于标准反射能快上不少.
- 自动重载: 插件能够监控到 Lua 脚本文件的更改, 并自动重新加载脚本文件.
不过依托于Java的反射机制和动态代理机制, 目前可以实现在lua脚本中继承Java接口,调用Java类型中的任何公开方法, 公开属性. 也就是说本插件可以动态的加载脚本, 享受Java的子集功能. 当然, 反射也不是万能的, 还是会出现很多Lua端无法处理的情况, 此时就需要使用Java为Lua架桥了. 不过在开发过程中我会尽量简化Lua与Java中的交互流程.
除开上述所说内容, 与第一代相同, 还能够加载C/C++所编写的动态链接库. 当然这都是 Lua 语言本身就支持的功能.
Lua 的池化
依托于 luajava 的不懈努力, 现在可以在多个线程上执行不同的 Lua 代码.
在本插件中, 每个 Lua 环境配置都拥有一个主要的 Lua 虚拟机.
在没有池化 Lua 虚拟机时, 主Lua虚拟机正在运行的同时, 另外一个线程B需要获取主Lua虚拟机的运行权(如 Bukkit 事件触发时, 或 Bukkit 的异步任务)去运行 Lua 的代码(如 Lua 的闭包函数), 此时线程B需要阻塞等待主Lua虚拟机, 当主Lua虚拟机当前任务完成后, 线程B才能获取到主Lua虚拟机的运行权去运行 Lua 代码; 并在等待运行完 Lua 代码后, 才能释放主Lua虚拟机的运行权. 假设线程B执行的代码耗时非常长, 则会导致 主Lua虚拟机 一直被线程B所占用, 阻塞其他 Lua 代码的执行, 直到线程B释放运行权.
而在拥有 Lua 池后, 相同的情况下, 线程B在获取到 主Lua虚拟机 运行权后, 会将即将执行的Lua代码及所有相关的数据全部转移到 其他Lua虚拟机 中, 转移完成后会立即释放 主Lua虚拟机 的运行权, 而去获取 其他Lua虚拟机 的运行权去运行刚刚转移的代码. 此时线程B就能做到在获取到 主Lua虚拟机 运行权的极短时间内释放运行权, 而不必等待 Lua 代码运行完毕, 以保证 主Lua虚拟机 能够快速响应其他调用.
这里举一个更加具体的例子, 如下代码会调用两次Bukkit的异步任务, 并且要执行的异步任务都是无限循环.
local import = require "import"
local Thread = import "java.lang.Thread"
for i = 1, 2 do
luaBukkit.helper:asyncCall(luaBukkit.env:pooledCallable(
function ()
while true do
luaBukkit.log:info(Thread:currentThread():getName() .. " async call " .. i .. "!")
Thread:sleep(1000)
end
end
))
end
当启用 Lua 池, 并且容量大小为 2 时, 上述代码输出以下内容, 可以看到有多个线程的输出, 并且能够响应 stop
指令关闭服务器:
[13:14:41 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 3 - LuaInMinecraftBukkitII async call 1!
[13:14:41 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 1 - LuaInMinecraftBukkitII async call 2!
[13:14:42 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 1 - LuaInMinecraftBukkitII async call 2!
[13:14:42 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 3 - LuaInMinecraftBukkitII async call 1!
禁用 Lua 池功能后, 上述代码输出以下内容, 可以看到仅有一个线程的输出, 并且虽然能够响应 stop
指令, 但是无法关闭服务器, 因为尝试释放 Lua 虚拟机资源时无法从死循环情况下获取到运行权:
[13:17:49 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
[13:17:52 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
stop
[13:17:53 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
[13:17:53 INFO]: Stopping the server
[13:17:53 INFO]: Stopping server
[13:17:53 INFO]: [LuaInMinecraftBukkitII] Disabling LuaInMinecraftBukkitII vmaster-59748d7+luajava-master-a3ddaf6+java-21
[13:17:53 INFO]: [LuaInMinecraftBukkitII] [LuaEnv default] Shutdown auto-reload.
[13:17:54 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
[13:17:55 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
[13:17:56 INFO]: [LuaInMinecraftBukkitII] Craft Scheduler Thread - 2 - LuaInMinecraftBukkitII async call 2!
JNIBridge
多亏了 cffi 的加持, JNIBridge 为此而生! 现在能够与动态链接库进行交互了. 目前 JNIBridge 还在完善中, 现支持功能有:
下一阶段计划支持的功能有:
下图是一个简单的玩家加入服务器事件, 不过事件处理逻辑由 CPP 端处理.

支持的服务器核心
本插件支持大量的服务器核心, 基本上支持 BUKKIT API 的服务器核心都能够支持, 例如: Bukkit, Spigot, Paper, Mohist 等等. 目前在 1.7.10 的 Mod 端上主体功能运行良好.
此外在 1.0.9 版本开始, 增加了对 Folia 服务端的支持.
下载地址
目前下载地址可以前往 Spigot, Modrinth 或者 Github 页面进行下载.
对于高版本用户或Folia服务端用户(或使用 Java17+ 运行服务端的用户)可以直接下载文件名中带有 +folia
字样的文件版本.
对于选择在 Github 页面中下载的用户, 请确保下载文件名带有 -all
结尾的 jar 包.
安装方式
仅需要将插件放入 plugins
文件夹中即可. 插件会在加载时, 检测运行环境并自动获取匹配的动态链接库.
由于插件本身未打包动态链接库, 并且动态链接库存放在 Github 仓库中, 若遭遇网络困难, 可能需要手动安装动态链接库. 可以先前往仓库中下载 natives.json
以及对应系统和版本的 luajava
动态链接库后, 放入 /plugins/LuaInMinecraftBukkitII/natives
文件夹下即可.
指令
插件指令仅 op 可用, 可以在服务器中输入 /lua help
查看拥有的指令.
文档
本插件拥有较为详细的文档, 可以选择前往 Github 页面, 或者我的 博客 页面浏览相关文档.
已知问题
注意: 标记为[ ]
的代表未修复, 标记为 [x]
代表已经修复
[ ] 对于 Mohist 等 Mod/Bukkit 混合端将无法正常使用指令注册功能, 或指令注册仅首次加载有效, 重载 Lua 环境后失效.
[ ] FastReflection 快速反射目前遇到无法生成的字节码时将会直接报错, 而不会回退到标准反射.
[x] 无法正常处理 Emoji 文本 (1.0.9已修复)
[x] 无法正常调用接口类中定义的默认方法 (1.0.9已修复)
[x] 提交任务至 Lua 池时随机崩溃 JVM (1.0.9已修复)
[x] Windows 无法正常下载 LuaJIT 的动态链接库 (1.0.9已修复)
[x] Lua脚本中无法读取类中公共静态变量 (1.0.7已修复)
[x] LuaHelper 中的 castArray
方法始终失败 (1.0.7已修复)
声明
本插件极大部分代码均为原创,不存在借用/抄袭等行为, 本插件所使用的 luajava 由 luajava-jasonsantos 分叉而来
本插件源代码以 MIT 协议进行开源
