Skip to content

外部插件 API ​

自 v6.2.2 起

UltiTools-API 6.2.2 及更高版本可用。

外部插件 API 允许任何普通的 Bukkit/Spigot 插件使用 UltiTools 框架功能,无需继承 UltiToolsPlugin。你的插件保持普通的 JavaPlugin 不变——只需调用 UltiToolsAPI.connect(this),框架就会扫描你的包中的 @Service、@CmdExecutor、@EventListener、@Scheduled 等注解。

快速开始 ​

1. 添加依赖 ​

Maven

xml
<dependency>
    <groupId>com.ultikits</groupId>
    <artifactId>UltiTools-API</artifactId>
    <version>6.2.5</version>
    <scope>provided</scope>
</dependency>

2. 在 plugin.yml 中声明依赖 ​

yaml
name: MyExternalPlugin
version: '1.0.0'
main: com.example.myplugin.MyExternalPlugin
depend: [UltiTools]

WARNING

depend: [UltiTools] 是必须的。UltiTools 必须在你的插件之前加载,这样调用 connect() 时框架才可用。

3. 连接和断开 ​

java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

public class MyExternalPlugin extends JavaPlugin {

    @Override
    public void onEnable() {
        UltiToolsAPI.connect(this);
        // Your plugin is now wired into UltiTools!
    }

    @Override
    public void onDisable() {
        UltiToolsAPI.disconnect(this);
    }
}

就这样。框架会自动扫描 com.example.myplugin(从主类名推导出)中的注解类。

扫描内容 ​

调用 connect() 时,框架扫描你插件的基础包并注册:

注解功能
@Service注册为 IoC 容器中的 Bean
@CmdExecutor命令类自动注册到 Bukkit
@EventListener监听器自动注册到 Bukkit
@Scheduled方法注册为 Bukkit 定时任务
@PlayerCache字段按玩家跟踪,自动保存/加载
@ModuleEventHandler订阅 UltiTools 事件总线

编写服务 ​

服务的写法与 UltiTools 模块完全一样——使用 @Service 和 @Autowired:

java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

@Service
public class GreetingService {

    @Autowired
    private StatsService statsService; // Injected by the IoC container

    public void greetPlayer(Player player) {
        player.sendMessage("Welcome! You have " + statsService.getVisits(player) + " visits.");
    }
}

编写命令 ​

像 UltiTools 模块一样使用 @CmdExecutor 和 @CmdMapping:

java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

@CmdExecutor(alias = {"greet"}, permission = "myplugin.greet", description = "Greet command")
@CmdTarget(CmdTarget.CmdTargetType.PLAYER)
public class GreetCommand extends BaseCommandExecutor {

    @Autowired
    private GreetingService greetingService;

    @CmdMapping(format = "")
    public void greet(@CmdSender Player player) {
        greetingService.greetPlayer(player);
    }

    @Override
    protected void handleHelp(CommandSender sender) { }
}

TIP

命令描述使用 @CmdExecutor 的原始 description 属性。外部插件不支持 i18n() 方法——请使用纯字符串。

编写事件监听器 ​

java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

@EventListener
public class JoinListener implements Listener {

    @Autowired
    private GreetingService greetingService;

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        greetingService.greetPlayer(event.getPlayer());
    }
}

数据存储 ​

使用 UltiToolsAPI.getDataOperator() 获取数据操作器。数据存储在你插件自己的数据文件夹中,而不是 UltiTools 的文件夹。

java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

@Data @Builder @NoArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("player_stats")
public class StatsEntity extends BaseDataEntity<String> {
    @Column("player_id") private String playerId;
    @Column("visits") private int visits;
}
java
package com.ultikits.docs.external;

import com.ultikits.ultitools.abstracts.command.BaseCommandExecutor;
import com.ultikits.ultitools.abstracts.data.BaseDataEntity;
import com.ultikits.ultitools.annotations.*;
import com.ultikits.ultitools.annotations.command.*;
import com.ultikits.ultitools.api.UltiToolsAPI;
import com.ultikits.ultitools.interfaces.DataOperator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.UUID;

@Service
public class StatsService {

    private final DataOperator<StatsEntity> dataOp;

    public StatsService() {
        JavaPlugin plugin = JavaPlugin.getPlugin(MyExternalPlugin.class);
        this.dataOp = UltiToolsAPI.getDataOperator(plugin, StatsEntity.class);
    }

    public int getVisits(Player player) {
        StatsEntity stats = dataOp.query()
            .where("player_id").eq(player.getUniqueId().toString())
            .first();
        return stats != null ? stats.getVisits() : 0;
    }
}

TIP

存储后端(JSON、SQLite 或 MySQL)由 UltiTools 服务端配置决定,而非你的插件。你的代码无论使用哪种后端都一样。查询列名必须使用实体的 @Column 值,而不是 Java 字段名。

事件总线 ​

使用 UltiToolsAPI.getEventBus() 进行插件间通信:

java
// 发布事件(MyCustomEvent 必须继承 ModuleEvent)
UltiToolsAPI.getEventBus().publish(new MyCustomEvent(data));

// 在 @Service 类中通过注解订阅
@ModuleEventHandler
public void onCustomEvent(MyCustomEvent event) {
    // 处理来自任何模块或外部插件的事件
    // 参数类型不继承 ModuleEvent 时会被跳过,只打一条 WARNING 日志,不会注册
}

API 参考 ​

方法描述
UltiToolsAPI.connect(JavaPlugin)将插件连接到 UltiTools 框架
UltiToolsAPI.disconnect(JavaPlugin)断开插件与框架的连接
UltiToolsAPI.isConnected(JavaPlugin)检查插件是否已连接
UltiToolsAPI.getDataOperator(JavaPlugin, Class)获取限定在插件数据文件夹的 DataOperator
UltiToolsAPI.getEventBus()获取共享的 EventBus 实例

生命周期 ​

  • 自动断开:如果你的插件被禁用(服务器停止、/reload),UltiTools 会通过 PluginDisableEvent 监听器自动断开连接。你不一定需要在 onDisable() 中调用 disconnect(),但这是个好习惯。
  • UltiTools 关闭:当 UltiTools 自身关闭时,所有外部插件会通过 disconnectAll() 自动断开。
  • 清理:断开连接时,你的插件注册的所有命令、监听器、定时任务、事件总线订阅和玩家缓存 Bean 都会被移除。

与 UltiTools 模块的区别 ​

功能UltiTools 模块外部插件
基类extends UltiToolsPluginextends JavaPlugin
注册方式@UltiToolsModule + registerSelf()UltiToolsAPI.connect(this)
国际化plugin.i18n("key") 可用不可用——使用纯字符串
配置实体完整支持(@ConfigEntity)不可用 — 请使用 Bukkit getConfig()
绑定到配置项的 @Scheduled / @CmdCD(v6.3.0+)支持,见绑定到配置项的时间会被拒绝,请使用字面量 period / delay / value
数据存储plugin.getDataOperator(Class)UltiToolsAPI.getDataOperator(plugin, Class)
热重载支持 ul reload不支持——需要重启服务器
plugin.ymlapi-version: 620;使用了绑定到配置项的 @Scheduled / @CmdCD 时为 630depend: [UltiTools]

完整示例项目 ​

查看 UltiTools-External-Example 仓库,获取一个完整的示例项目,演示了在标准 Bukkit 插件中使用 @Service、@CmdExecutor、@EventListener、@Autowired 和 DataOperator CRUD。

贡献者

The avatar of contributor named as Ling Bao Ling Bao
The avatar of contributor named as Claude Opus 5.5 (1M context) Claude Opus 5.5 (1M context)

基于 MIT 许可发布