Linlang 运行时为每一个使用它的插件创建独立的服务副本。您需要在插件启用时完成初始化,保存返回的 Linlang 实例,并在插件卸载时关闭它。
在 Bukkit 平台中,初始化入口是 Lin:
import api.linlang.runtime.Lin;
import api.linlang.runtime.Linlang;
最简单的初始化方式是在插件主类的 onEnable() 中调用 Lin.init(this):
public final class MyPlugin extends JavaPlugin {
private Linlang lin;
@Override
public void onEnable() {
lin = Lin.init(this);
}
@Override
public void onDisable() {
if (lin != null) {
lin.close();
lin = null;
}
}
}
这里的 this 是当前插件的 JavaPlugin 实例,也是 Linlang 在 Bukkit 平台中的「平台上下文」。运行时使用它确定文件根目录、日志通道、命令所有者和事件监听器所属插件。
Lin.init(this) 会先从 Maven 构建元数据或 META-INF/linlang/required-api.properties 检测插件编译时使用的 API 版本,然后完成以下操作:
ServicesManager 中发现 Linlang 运行时。JavaPlugin 注入为平台上下文。Linlang 实例。如果服务器没有安装可用的运行时,初始化会抛出 IllegalStateException。因此,请先按照 依赖引入 ⇱ 的说明,在 plugin.yml 中声明 LinlangRuntimeBukkit 为前置插件。
如果您在启动时已经知道语言、消息前缀和日志方式,我们推荐使用 Lin.setup(...)。它会在一次初始化流程中应用 LinOptions,最后统一刷新服务:
import api.linlang.runtime.Lin;
import api.linlang.runtime.LinOptions;
import api.linlang.runtime.Linlang;
public final class MyPlugin extends JavaPlugin {
private Linlang lin;
@Override
public void onEnable() {
lin = Lin.setup(this, new LinOptions()
.pluginLogger(true)
.totalPrefix("§7[§dMyPlugin§7]§r")
.totalLocale("zh_CN"));
}
@Override
public void onDisable() {
if (lin != null) {
lin.close();
lin = null;
}
}
}
这些方法的含义是:
pluginLogger(true):让 Linlang 日志通过当前插件的 Logger 输出。totalPrefix(...):设置 Linlang 内建消息使用的前缀。totalLocale(...):设置当前 Linlang 实例的全局语言。如果前缀需要根据平台上下文动态生成,可以使用:
lin = Lin.setup(this, new LinOptions()
.dynamicTotalPrefix(context -> {
JavaPlugin plugin = (JavaPlugin) context;
return "§7[§a" + plugin.getName() + "§7]§r";
})
.totalLocale("zh_CN"));
您应该在固定前缀与动态前缀中选择一种方式。对同一个 LinOptions 先后调用两者时,后调用的会覆盖前一个的设置。
部分插件需要先读取自己的配置文件,再决定 Linlang 使用的语言或前缀。此时可以使用带回调的 Lin.setup(...):
lin = Lin.setup(this, current -> {
MainConfig config = current.linFile().config().bind(MainConfig.class);
return new LinOptions()
.pluginLogger(true)
.totalPrefix(config.prefix)
.totalLocale(config.language);
});
回调参数 current 是已经创建、但尚未执行最终刷新流程的 Linlang 门面。您可以从中绑定配置对象,然后返回需要应用的 LinOptions。回调结束后,Linlang 会统一应用运行参数和个性化设置,再完成刷新。
这种写法可以减少「初始化一次、读取配置、修改设置、再次重载」带来的重复工作。配置对象的定义和绑定方式请见:配置文件 ⇱。
sequenceDiagram
participant Plugin as "您的插件"
participant Lin as "Lin"
participant Services as "Bukkit ServicesManager"
participant Runtime as "LinlangRuntimeBukkit"
participant Facade as "插件专属 Facade"
Plugin->>Lin: Lin.init(this) 或 Lin.setup(this, options)
Lin->>Services: 查找 Linlang 服务
Services-->>Lin: 返回运行时入口
Lin->>Runtime: createFacade(JavaPlugin)
Runtime-->>Lin: 返回插件专属 Facade
Lin->>Facade: 注入上下文并刷新服务
Facade-->>Plugin: 返回 Linlang 实例
运行时入口是所有插件共享的,但 Facade 不是。每个 Facade 持有当前插件对应的文件服务、命令服务、消息服务、界面服务与语言状态。这种结构使 Linlang 可以复用底层运行能力,同时隔离不同插件的资源和生命周期。
Runtime 的启动顺序、资源所有权、软重载、设置更新和服务器关闭流程请见:琳琅运行时 ⇱。
初始化完成后,所有开发者服务均通过保存的 lin 实例获取:
lin.linFile();
lin.linCommand();
lin.linMessenger();
lin.linView();
建议在插件主类或专门的上下文类中保存同一个 Linlang 实例,再将其传递给需要使用服务的模块。不要在每次执行命令或处理事件时重复调用 Lin.init(this),否则会创建额外的 Facade,并增加重复注册和资源释放的复杂度。
初始化完成后,仍可通过统一的 settings() 修改设置:
lin.settings()
.totalPrefix("§7[§bNewPrefix§7]§r")
.apply();
lin.settings()
.totalLocale("en_GB")
.apply();
settings().apply() 原地应用语言、前缀及日志等设置,保留服务与命令注册。需要重新读取文件时,显式调用 lin.reload()。详见重载机制 ⇱。
插件卸载时调用 lin.close()。该方法会注销当前插件创建的 Facade,并释放它持有的命令、监听器、文件监视器和其他运行资源。
请不要关闭由 Lin.find() 返回的共享运行时入口,也不要自行实例化 Core 或 Bukkit 实现类。插件开发代码应始终通过 Lin.init(...) 或 Lin.setup(...) 获取自己的服务门面。
讨论