未发布版本 v6.3.0-SNAPSHOT。 本页内容来自 alpha 分支,随时可能变更,不属于任何已发布版本。

commit 49619c6 · 注入于 2026-09-13 12:21 UTC

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()
数据存储plugin.getDataOperator(Class)UltiToolsAPI.getDataOperator(plugin, Class)
热重载支持 ul reload不支持——需要重启服务器
plugin.ymlapi-version: 620depend: [UltiTools]

完整示例项目

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

贡献者

暂无相关贡献者

基于 MIT 许可发布