Skip to content

动画系统 ​

CoreLib 动画系统的构成, 第三方插件可用的 API, 以及它和 EmakiMobs 的分工如下

EmakiCoreLib 动画系统给各个模块提供一套共用的动画时序能力: 注册动画定义, 按 1/20 秒 (一个游戏刻) 精确触发关键帧 (K帧), 按优先级抢占并裁决冲突, 监听播放的整个生命周期. 它只管"什么时候发生什么", 不碰任何模型渲染 -- 动画实际怎么播出来, 交给用它的模块 (例如 EmakiMobs) 通过自己的模型后端桥接层去做

核心概念 ​

概念类型说明
动画定义AnimationDefinition一个不可变的 record, 记着 id, 引擎动画名 (engineAnimation, CoreLib 不解释它), 时长 (以游戏刻计), 是否循环, 优先级, 冲突策略, 以及关键帧列表
关键帧AnimationKeyframe播放开始后的第 tick 个游戏刻触发; 它带的内容是一行 CoreLib 动作管道, 可以为空, 空帧只用来发监听通知
优先级AnimationPriority分 AMBIENT < UTILITY < ACTION < REACTIVE < TERMINAL 五档, 高档能抢占低档
冲突策略AnimationConflictPolicy优先级相同时, 选 REPLACE (替换掉旧的) 还是 REJECT (拒绝新的请求)
播放句柄AnimationPlaybackHandle有 PLAYING / FINISHED / CANCELLED 三种状态; cancel() 重复执行结果一样
播放监听AnimationListener有 onPlay / onKeyframe / onStop 三个回调, 在实体 owner 线程上运行

第三方插件 API ​

要用这套 API, 先依赖 emaki-corelib-api (provided, 禁止 shade). 所有入口都在 EmakiCoreLibApi 下:

java
// 注册动画定义 (owner-scoped, 可撤销; 注册表在 CoreLib reload 后存活, 无需重建回调)
AnimationRegistration reg = EmakiCoreLibApi.registerAnimation(plugin,
    AnimationDefinition.of("my_boss_slam", "slam_anim", 30, false,
        AnimationPriority.ACTION, AnimationConflictPolicy.REPLACE,
        List.of(
            AnimationKeyframe.of(0, "self | play_sound sound=minecraft:entity.wither.shoot", "windup"),
            AnimationKeyframe.of(12, "self | spawn_particle particle=explosion", "impact")
        )));

// 播放 (任意线程可调; future 完成线程不固定)
CompletableFuture<EmakiResult<AnimationPlaybackHandle>> future =
    EmakiCoreLibApi.playAnimationAsync(plugin, entity, "my_boss_slam",
        CoreActionExecutionContext.builder().caster(entity).phase("animation").build());

// 停止 / 监听
EmakiCoreLibApi.stopAnimation(plugin, entity, "my_boss_slam");
AnimationRegistration listener = EmakiCoreLibApi.addAnimationListener(plugin, new AnimationListener() {
    @Override public void onPlay(Entity e, AnimationDefinition d, UUID id) {
        // 在这里把 d.engineAnimation () 转发给你的模型后端
    }
});

线程与生命周期规则 ​

  • playAnimationAsync 任何线程都能调; K帧的动作行在实体 owner 线程上执行 (Folia 下也安全), 调度交给 CoreLib 的 ExecutionDispatcher
  • 关键帧的内容由共用的动作引擎编译, 并按行缓存; 某行编译失败就打一条警告并跳过, 不影响其余帧
  • 记得在 onDisable 里关掉句柄; owner 插件被禁用时, 它的注册和正在播放的动画会自动撤销
  • 动画定义注册表在 CoreLib reload 后还在, 不用重建回调; 需要在 reload 后重新注册的是动作段表 (registerActionStage 等), 它会在 reload 时被重建, 必须用 onStageRegistryRebuilt / addStageRegistryRebuildListener 把注册重放一遍
  • 没装 CoreLib 时, 所有入口都返回固定的 unavailable/inactive 对象, 不会抛异常

与 EmakiMobs 的分工 ​

层归属内容
时序基础设施EmakiCoreLib动画定义注册表, K帧调度, 优先级裁决, 监听分发
模型渲染桥EmakiMobsModelEngine / BetterModel 桥接, 解释 engineAnimation, 以及 LOD
玩法映射EmakiMobs把 idle/walk/run/attack/hurt/death 等标准动作和触发器绑在一起

怪物自身的规则 (哪个生物配哪个蓝图, 受伤播哪个动画) 不进 CoreLib; CoreLib 也不引用任何模型插件的类

配置 ​

动画系统本身没有配置节; K帧的时长, 优先级, 冲突策略全部由注册方决定, 你不用在这里调. 用它的模块的模型/LOD 配置见 EmakiMobs 实体模型与动画