- 版权类型
- 原创
- 插件中文名称
- Lua在桶里汪汪叫2
- 插件英文名称
- LuaInMinecraftBukkit II
- 原帖地址
- #
- 支持的核心(服务端)
- Spigot
- Paper
- Folia
- Purpur
- 其他核心
- 语言支持
- 中文(简体)
- 适配版本(Java)
- 1.21
- 1.20
- 1.19
- 1.18
- 1.17
- 1.16
- 1.15
- 1.14
- 1.13
- 1.12
LuaInMinecraftBukkit II
在你的服务器中运行Lua吧!
GitHub | 文档 | Lua Side API | 快速使用 | 事件监听 | 指令注册
与上一代 LuaInMinecraftBukkit 相比, 本代主要聚焦特化Lua原生版本, 并且增加了多核运行 Lua 脚本的能力, 目的是为了提供一个更加易用的插件. 目前本插件支持系统包含MacOS Linux, 以及Windows. 支持的Lua版本包含: Lua5.1(LuaJIT), Lua5.2, Lua5.3, Lua5.4.
若遇到问题欢迎去github上提交issue.
交流群: 662312388
[MD] [luajava-jasonsantos]: https://github.com/jasonsantos/luajava [luajava-smileyik]: https://github.com/SmileYik/luajava [lua-pool-example]: https://github.com/SmileYik/LuaInMinecraftBukkitII/blob/gh-page/docs/en/GlobalVariable.md#pooledcallable---transform-a-lua-closure-into-a-closure-that-can-be-run-in-the-lua-pool [jni-bridge]: https://github.com/SmileYik/LuaInMinecraftBukkitII/modules/jni-bridge ## 简介 LuaInMinecraftBukkit II 是一个 Minecraft Bukkit 服务端插件, 目的是实现使用 Lua 脚本与 Bukkit 服务器交互. Lua 是一个小巧的脚本语言, 拥有非常简单的语法, 还有着较为不错的运行速度. 试想一下, 用一个轻巧的, 不需要编译就可以运行的脚本编写Bukkit插件将多么美好. 如果要修改一个地方, 那就修改, 然后重新加载脚本就好了, 简直就像梦一样. ## 与上一代的区别 相比于上一代, 本代更注重于Lua原生虚拟机. 同样的, 本代也基于[luajava][luajava-jasonsantos]项目.不过与上一代相比, 本代使用[克隆后的luajava][luajava-smileyik]仓库. 与原仓库相比, 克隆后的luajava仓库基本上重写了反射部分功能, 能够进一步简化Lua调用Java方法之间的过程, 并且在C语言端提供了非常友好的异常提示. ## 能做什么? 本插件主要有三大功能: + 注册指令: 注册你想要的任何指令, 并且自动生成帮助信息和指令层级关系 + 监听事件: 监听任何你想要的Bukkit事件, 即使这个事件是其他插件的自定义事件 + Lua池化: 将 Lua 池化后, 允许提交 Lua 闭包至其他状态机上运行, 以获取真正的多线程并行运行能力: [示例][lua-pool-example] 其他功能有: + 快速反射: 现在, 为 Lua 的反射组件接入了以 MethodHandle 为基础的快速反射, 相比于标准反射能快上不少. + 自动重载: 插件能够监控到 Lua 脚本文件的更改, 并自动重新加载脚本文件. 不过依托于Java的反射机制和动态代理机制, 目前可以实现在lua脚本中继承Java接口,调用Java类型中的任何公开方法, 公开属性. 也就是说本插件可以动态的加载脚本, 享受Java的子集功能. 当然, 反射也不是万能的, 还是会出现很多Lua端无法处理的情况, 此时就需要使用Java为Lua架桥了. 不过在开发过程中我会尽量简化Lua与Java中的交互流程. 除开上述所说内容, 与第一代相同, 还能够加载C/C++所编写的动态链接库. 当然这都是 Lua 语言本身就支持的功能. ## Lua 的池化 依托于 [luajava][luajava-smileyik] 的不懈努力, 现在可以在多个线程上执行不同的 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的异步任务, 并且要执行的异步任务都是无限循环. ```lua 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][jni-bridge] 为此而生! 现在能够与动态链接库进行交互了. 目前 JNIBridge 还在完善中, 现支持功能有: + [x] Java 方法调用 + [x] 基础类型转换 下一阶段计划支持的功能有: - [ ] 字段访问与赋值 - [ ] 数组访问与赋值 下图是一个简单的玩家加入服务器事件, 不过事件处理逻辑由 CPP 端处理.  ## 支持的服务器核心 本插件支持大量的服务器核心, 基本上支持 BUKKIT API 的服务器核心都能够支持, 例如: Bukkit, Spigot, Paper, Mohist 等等. 目前在 1.7.10 的 Mod 端上主体功能运行良好. 此外在 1.0.9 版本开始, 增加了对 Folia 服务端的支持. ## 下载地址 [Spigot]: https://www.spigotmc.org/resources/luainminecraftbukkit-ii.126395/history [Modrinth]: https://modrinth.com/plugin/luainminebukkit/versions [GithubRelease]: https://github.com/SmileYik/LuaInMinecraftBukkitII/releases [NativeResource]: https://github.com/SmileYik/LuaInMinecraftBukkitII/tree/gh-page/natives 目前下载地址可以前往 [Spigot], [Modrinth] 或者 [Github][GithubRelease] 页面进行下载. 对于**高版本用户**或**Folia服务端用户**(或使用 Java17+ 运行服务端的用户)可以直接下载文件名中带有 `+folia` 字样的文件版本. 对于选择在 [Github][GithubRelease] 页面中下载的用户, 请确保下载文件名带有 `-all` 结尾的 jar 包. ## 安装方式 仅需要将插件放入 `plugins` 文件夹中即可. 插件会在加载时, 检测运行环境并自动获取匹配的动态链接库. 由于插件本身未打包动态链接库, 并且动态链接库存放在 Github 仓库中, 若遭遇网络困难, 可能需要手动安装动态链接库. 可以先前往[仓库][NativeResource]中下载 `natives.json` 以及对应系统和版本的 `luajava` 动态链接库后, 放入 `/plugins/LuaInMinecraftBukkitII/natives` 文件夹下即可. ## 指令 插件指令仅 op 可用, 可以在服务器中输入 `/lua help` 查看拥有的指令. ## 文档 [GithubDocs]: https://github.com/SmileYik/LuaInMinecraftBukkitII/tree/gh-page/docs [BlogDocs]: https://blog.smileyik.eu.org/?blog=other&album=LuaInMinecraftBukkit&post=zh 本插件拥有较为详细的文档, 可以选择前往 [Github][GithubDocs] 页面, 或者我的 [博客][BlogDocs] 页面浏览相关文档. ## 已知问题 注意: **标记为`[ ]`的代表未修复, 标记为 `[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-smileyik] 由 [luajava-jasonsantos] 分叉而来** **本插件源代码以 MIT 协议进行开源**  [/MD]