正在载入

等待时间过长时请刷新页面

编写于

最近更新

琳琅运行时

琳琅运行时是安装在 Minecraft 服务器中的插件,插件名为 LinlangRuntimeBukkit。它提供 Linlang 的具体功能,并负责管理这些功能的生命周期。

服务器只需要安装一个运行时。每个使用 Linlang 的插件会从这个运行时取得一个独立的 Linlang 对象,这个对象称为 Facade,也就是当前插件的服务入口。

可以把两者理解为:

  1. Runtime:服务器中共享的功能实现。
  2. Facade:Runtime 为某个插件创建的独立服务实例。

插件只依赖 linlang-api 编写代码,不直接依赖 Runtime、Core 或 Bukkit 实现类。

工作原理

运行时启动后,会向 Bukkit ServicesManager 注册一个 Linlang 服务。使用方插件调用 Lin.init(this)Lin.setup(this, options) 时,API 找到这个服务,并要求运行时为当前 JavaPlugin 创建 Facade。

flowchart LR
    Server["Bukkit / Paper"] --> Runtime["LinlangRuntimeBukkit"]
    Runtime --> Services["ServicesManager"]
    Plugin["使用 Linlang 的插件"] -->|"Lin.setup(this)"| Services
    Services --> Runtime
    Runtime --> Facade["当前插件的 Linlang Facade"]
    Facade --> Modules["文件、命令、消息、界面、审计"]

在代码内部:

  1. BukkitLoader 负责启动和关闭运行时插件。
  2. RuntimeCore 保存服务器级共享资源,并创建、登记和关闭 Facade。
  3. FacadeCore 管理某个插件的服务与生命周期。
  4. BukkitPlatformAdapter 把 Core 的请求转换为 Bukkit API 操作。

Linlang 向开发者提供唯一入口 Lin

资源如何隔离

不同插件共享 Runtime 的实现代码,但各自保存业务数据。

运行时共享每个插件独立
Bukkit 平台适配器配置服务与语言服务
运行时事件总线命令服务与消息服务
日志与审计 Provider全局语言与消息前缀
内建消息和问题代码Facade 事件总线
服务创建与关闭逻辑文件目录与审计租户

运行时根据传入的 JavaPlugin 判断资源属于哪个插件。插件 A 的配置文件不会写入插件 B 的目录,插件 A 的命令、语言和日志设置也不会修改插件 B 的 Facade。

界面核心和数据服务由 Runtime 按插件所有者管理,同样不会在不同插件之间混用。

安装与使用

服务器管理员需要将 linlang-runtime-bukkit Jar 放入服务器的 plugins 目录。插件项目只以 provided 方式依赖相同版本的 linlang-api,并在 plugin.yml 中声明:

depend:
  - LinlangRuntimeBukkit

这样 Bukkit 会先启用运行时,再启用依赖 Linlang 的插件。依赖与开发环境配置请见:依赖引入 ⇱

插件在 onEnable() 中初始化,在 onDisable() 中关闭:

public final class MyPlugin extends JavaPlugin {

    private Linlang lin;

    @Override
    public void onEnable() {
        lin = Lin.setup(this, new LinOptions()
                .pluginLogger(true)
                .totalLocale("zh_CN"));
    }

    @Override
    public void onDisable() {
        if (lin != null) {
            lin.close();
            lin = null;
        }
    }
}

初始化后,从同一个 lin 获取服务:

lin.linFile();
lin.linCommand();
lin.linMessenger();
lin.linView();
lin.linAudit();

Lin.init(this) 使用默认设置。Lin.setup(this, options) 会在初始化时同时应用语言、前缀和日志方式。更多初始化写法请见:初始化 ⇱设置项 ⇱

每个插件启用周期只应初始化一次。不要在命令或事件中重复调用 Lin.init(this),否则会为同一个插件创建额外的 Facade。

Lin.find() 返回共享运行时入口,不是插件自己的 Facade。普通插件不应修改或关闭它。

版本兼容

运行时会在启动和插件初始化时检查版本兼容性。兼容规则、插件依赖版本的声明方式以及后续更新查询入口,请见:版本兼容性 ⇱

生命周期

2.6.0.0 开始,日常设置和重载都保留 Facade 及其服务实例。切换语言不再清空命令注册,也不需要重新绑定文件对象。

操作实际行为
lin.reload()刷新审计配置、配置和语言;成功后执行插件回调,再刷新 GUI 定义
lin.settings().apply()原地应用设置,切换语言时加载目标语言,不重读无关配置
lin.restart()重建文件、命令、消息与 GUI 服务,执行插件的重建回调
lin.close()关闭门面并释放资源

Bukkit 中应在主线程调用这些操作。递归重载、重载期间关闭,以及使用已关闭的 Facade 都会被拒绝。

业务缓存不会自动从配置对象重新计算。插件可以通过具名 onReload 回调更新缓存;完整顺序、失败处理和旧版迁移见重载机制 ⇱

关闭

lin.close() 会注销当前 Facade,关闭命令交互和消息资源,停止 Facade 事件总线,并释放当前插件的界面、数据和审计资源。

服务器关闭时,Runtime 会先从 Bukkit 注销共享服务,阻止继续创建 Facade;随后关闭仍然存在的 Facade、运行时事件总线和数据资源,最后刷新审计文件队列。

Runtime 会清理未关闭的残留 Facade,但插件仍应在自己的 onDisable() 中主动调用 lin.close()

运行时命令

运行时提供 /linlang 管理命令,权限为 linlangruntimebukkit.admin,默认授予 OP。

命令作用
/linlang help查看运行时命令帮助。
/linlang info查看 API 与 Runtime 版本。
/linlang plugins查看已经创建 Facade 的插件。
/linlang reload <插件名称>只软重载指定插件的 Facade。
/linlang reload-all软重载 Runtime 和全部 Facade。
/linlang restart <插件名称>重建指定插件的门面服务;插件须先注册重建回调。
/linlang restart-all逐个重建已注册插件的门面服务,汇总成功数量。
/linlang problems查看全部内建问题代码。
/linlang problem <代码>查询问题代码的含义。

运行时命令的前缀、执行结果、列表标题、字段名称、命令说明和参数名称位于:

plugins/LinlangRuntimeBukkit/linlang/runtime/command/zh_CN.yml
plugins/LinlangRuntimeBukkit/linlang/runtime/command/en_GB.yml

您可以自行添加更多语言。

运行时按照自身的全局语言选择文件。单插件重载使用 reload-plugin 下的提示,全部重载使用 reload-all,旧的 reload 提示不再使用,避免升级后仍显示旧的全部重载文案。执行 /linlang reload-all 后,修改过的提示消息、命令帮助说明、参数名称和问题目录说明会通过语言引用立即生效,prefix 也会重新接入命令服务与消息服务。问题代码、组件标识和文档路径保持稳定;问题含义和处理建议由问题目录语言包提供,语言包不可用时使用 Runtime 内建文本。

restartrestart-all 会替换文件、命令、消息与 GUI 服务,但不调用插件的 onEnable()。插件必须通过 onRebuild 恢复文件绑定、命令和 GUI 注册;未提供回调时拒绝重建。旧 GUI 会话关闭,数据库和审计资源保留。

更新 Linlang 后应重新启动服务器以重新加载,不应使用任意形式的热重载。

讨论

请登录账号