Skip to content

API 与集成

第三方插件通过 emaki-mobs-api 访问 EmakiMobs 的生物定义。

Maven 坐标

xml
<repositories>
  <repository>
    <id>jiuwu-releases</id>
    <url>https://repo.crypticlib.com/repository/maven-public/</url>
  </repository>
</repositories>

<dependency>
  <groupId>emaki.jiuwu.craft</groupId>
  <artifactId>emaki-mobs-api</artifactId>
  <version>1.0.6</version>
  <scope>provided</scope>
</dependency>
kotlin
repositories { maven("https://repo.crypticlib.com/repository/maven-public/") }
dependencies { compileOnly("emaki.jiuwu.craft:emaki-mobs-api:1.0.6") }

仅编译依赖

runtime 已内嵌未 relocate 的 API 类。不要安装、bundle、shade 或 relocate API Jar;重复 ClassLoader 类型会破坏事件与 bridge。

paper-plugin.yml 里把 EmakiMobs 声明为依赖:

yaml
dependencies:
  server:
    EmakiMobs:
      load: BEFORE
      required: false
      join-classpath: true

门面

emaki.jiuwu.craft.mobs.api.EmakiMobsApi 是静态门面:

方法说明
status()可用性与身份元数据,返回 CoreLib 的 ApiStatus
catalog()查询层,见下文 MobCatalog
operations()操作层,见下文 MobOperations
extensions()扩展层,见下文 MobExtensions

访问器永不返回 null。EmakiMobs 缺失时 catalog 返回空答案,因此调用方不能把 NullPointerException 当作可用性信号。

MobCatalog 查询层

标注 @ApiStatus.NonExtendable

方法线程返回类型说明
definition(String mobId)任意线程Optional<MobDefinition>按 id 查询生物定义。
registeredIds()任意线程Set<String>列出所有已注册生物 id(不可变快照)。

所有方法返回不可变快照,线程安全。

MobOperations 操作层

方法返回类型说明
spawn(Location location, String mobId)Optional<LivingEntity>在指定位置生成一只已注册的自定义生物。location 的世界不可为 null,mobId 区分大小写;id 未注册或生成失败时返回空 Optional
remove(LivingEntity entity)void移除一只受管实体。接口 default 实现为空操作,真实实现由运行时桥提供。

EmakiMobs 缺失或尚未就绪时,operations() 返回的是安全的空操作实现,spawn 恒返回 Optional.empty()

生成实体属于 Bukkit 状态改动:在 Folia 上必须先切到该位置的 owner 线程再调用。

MobExtensions 扩展层

方法说明
registerCustomSpawner(String id, CustomSpawner spawner)注册自定义刷怪器;id 用于去重。

MobExtensions.CustomSpawner 是定义在 MobExtensions 内部的函数式接口,只有一个 onReload() 回调:注册时立即调用一次,之后每次 EmakiMobs 配置重载再调用一次。在其中读取最新配置并重新排程自己的刷怪任务。

java
EmakiMobsApi.extensions().registerCustomSpawner("my_spawner", () -> {
    // 注册时与每次 reload 后都会进入这里
    reloadMySpawnConfig();
});

MobDefinition 模型

暴露字段:

字段类型说明
id()StringYAML 文件与命令中使用的生物唯一 ID
entityType()EntityType底层原版实体类型
displayName()@Nullable StringMiniMessage 格式的自定义名;未设置时为 null
experience()int击杀经验覆盖值;0 表示沿用原版默认

不暴露的内部实现: componentsattributesskillsthreatboss_bar 均不在公共 API 中。这些字段属于内部配置,第三方插件无法查询。

不要缓存层对象

在使用点解析 catalog(),不要把它存进字段:backing bridge 在 reload 时会被替换

java
// 正确
EmakiMobsApi.catalog().definition("elite_zombie");

// 错误:reload 后这个引用会指向旧 bridge
private final MobCatalog cached = EmakiMobsApi.catalog();

示例

java
import emaki.jiuwu.craft.mobs.api.EmakiMobsApi;
import emaki.jiuwu.craft.mobs.api.MobCatalog;
import emaki.jiuwu.craft.mobs.api.model.MobDefinition;
import org.bukkit.entity.EntityType;

public class MyPlugin extends JavaPlugin {
    @Override
    public void onEnable() {
        if (!EmakiMobsApi.status().usable()) {
            getLogger().warning("EmakiMobs API 不可用");
            return;
        }
        
        MobCatalog catalog = EmakiMobsApi.catalog();
        
        // 查询单个生物定义
        catalog.definition("elite_zombie").ifPresent(mob -> {
            getLogger().info("找到生物:" + mob.displayName() 
                + "(类型:" + mob.entityType() 
                + ",经验:" + mob.experience() + ")");
        });
        
        // 列出所有已注册生物
        getLogger().info("已注册 " + catalog.registeredIds().size() + " 种生物");
        for (String mobId : catalog.registeredIds()) {
            catalog.definition(mobId).ifPresent(mob -> {
                if (mob.entityType() == EntityType.ZOMBIE) {
                    getLogger().info("  - " + mobId + " (僵尸变种)");
                }
            });
        }
    }
}

集成建议

  • 使用 definition() 在生物生成或交互时验证 id 是否为 EmakiMobs 管理的自定义生物。
  • registeredIds() 可用于 tab-complete 或配置验证。
  • MobDefinition 字段有限,主要用于基础信息展示。需要更多细节(如 components、attributes)时,考虑直接读取 EmakiMobs 的配置文件或使用实体 PDC 标记。