Skip to content

实体模型与动画 ​

自定义生物可以挂上 3D 模型, 并配置标准动作, K帧与距离分级 (LOD)

EmakiMobs 可以把自定义生物挂到 ModelEngine 或 BetterModel 渲染的 3D 模型上, 并驱动标准动作, 关键帧 (K帧) 事件与距离分级 (LOD). 两个模型后端都是可选依赖: 一个都没装时, 模型功能会不报错地关闭, 生物照样以原版形态运行

安装前提 ​

  1. 安装 ModelEngine (付费) 或 BetterModel (免费开源) 插件本体
  2. 在对应插件的 blueprints/ 目录放入 Blockbench 导出的 .bbmodel 蓝图, 并生成/接入含模型贴图的资源包
  3. 在 EmakiMobs 的 config.yml 的 model: 节选择后端 (见下文)
  4. 在生物定义的 YAML 里写 model: 节 (见下文)

蓝图名在两个后端里怎么解析由各自的插件决定; EmakiMobs 只按名字字符串去查, 不做额外加工

主配置 model: 节 ​

字段类型必填默认值取值范围说明
apistring否autoauto / model_engine / better_model (另接受别名 modelengine / bettermodel, 大小写不敏感)auto 会自动选 (先试 ModelEngine, 不行再试 BetterModel). 取值非法时预检报 WARN 并回退 auto; 指定或者选中的后端没安装时, 模型功能关闭并打印提示
view_distancedouble否48.0— (格)模型视距. NEAR 档按这个值设置可见范围; MID 档 ModelEngine 会收缩到 min(view_distance, mid), BetterModel 只给这个距离内的玩家生成模型; FAR 档 ModelEngine 视距归零, BetterModel 暂停 tracker
lod.neardouble否16.0需 ≤ lod.midLOD 的下界 (格). 距离不超过这个值就是 NEAR (完整视距)
lod.middouble否32.0需 ≥ lod.near, ≤ lod.farLOD 的中界 (格). near–mid 之间是 MID (降低了视距); 超过 mid 就算 FAR (mid–far 之间同样是 FAR), 所以它才是真正决定隐藏的那条界线
lod.fardouble否48.0需 ≥ lod.mid距离太远时提前结束判定的上界: 最近玩家的距离超过这个值就直接当成 FAR. 它小于 lod.mid 时, MID 档会有一部分距离永远用不到
movement_check_interval_ticksint否5≥ 1 (tick)多久检查一次移动状态 (idle/walk/run) 和 LOD; 只在档位或者状态变化时才下发给模型后端
death_detach_delay_ticksint否40≥ 0 (tick)死亡动画开始后, 再等多少 tick 才卸下模型实体
walk_speed_thresholddouble否0.12— (格/tick)水平速度达到这个值就算在行走
run_speed_thresholddouble否0.28— (格/tick)水平速度达到这个值就算在奔跑 (判定时先看这个阈值, 再看行走阈值)
transitions.<动作>_fade_ticksint否idle/walk/run 为 5, death 为 0, hurt 为 2, attack/skill/interact 为 3≥ 0 (tick)过渡混合的时长, 交给模型引擎自己补间. <动作> 只认 idle, walk, run, death, hurt, attack, skill, interact 这八个固定键, 其他键不会被读取; 负值按 0 处理

三档的行为: NEAR 用完整视距渲染; MID 降级 (ModelEngine 把视距收缩到 min(view_distance, mid), BetterModel 只给这个距离内的玩家生成模型); FAR 时 ModelEngine 把模型视距设成 0, BetterModel 暂停这个模型的 tracker

下面的示例把后端强制设为 BetterModel, 并把中距档收紧到 24 格:

yaml
model:
  api: "better_model"
  lod:
    near: 12.0
    mid: 24.0
    far: 48.0

生物定义 model: 节 ​

yaml
model:
  blueprint: "bone_lord"        # 必填: 模型蓝图名
  api: "model_engine"           # 可选: 覆盖全局 model.api, 为该生物指定后端
  scale: 1.2                    # 可选: 模型缩放, 默认 1.0
  animations:                   # 可选: 标准动作 → 引擎动画名映射
    idle: "breath"
    walk: "walk_slow"
    run: "run_fast"
    death: "die"
    hurt: "flinch"
    attack: "swing"
    skill: "cast"
    interact: "nod"
  keyframes:                    # 可选: 为任意动画定义 K帧时间轴
    attack:
      duration_ticks: 24        # 时间轴总长 (tick)
      loop: false               # 是否循环
      priority: "action"        # ambient|utility|action|reactive|terminal
      conflict: "replace"       # replace|reject 同优先级冲突策略
      frames:
        - tick: 0
          action: "self | play_sound sound=minecraft:entity.wither.shoot"
        - tick: 10
          label: "impact"
          action: "self | spawn_particle particle=flame"
  lod:                          # 可选: 覆盖全局 model.lod, 为该生物指定独立的档位边界
    near: 12.0
    mid: 24.0
    far: 40.0
字段类型必填默认值取值范围说明
blueprintstring是 (该节内)无后端 blueprints/ 中的蓝图名缺失或者空白时整节被忽略, 并打一条加载告警 (console.model_missing_blueprint). 运行时如果后端找不到这个蓝图, 会打 console.model_blueprint_missing 告警并跳过挂载
apistring否无 (继承全局 model.api)auto / model_engine / better_model这只生物用哪个模型后端, 会覆盖全局配置. 取值非法时打 loader.model_api_invalid 告警并回退到全局配置
scaledouble否1.0—模型的缩放倍率, 挂载和 mob_set_model 热切换时都会用到
animations.<动作键>string否无 (使用内置默认动画名)后端蓝图中存在的动画名动作键到引擎动画名的对应. 键名和值都会被规范化 (键转小写, 值去掉空白); 空白值会被忽略
keyframes.<动作键>section否无—K帧的时间轴; 键名就是动作键 (会规范化成小写). 不是标准动作的键 (不在 idle... interact 之内) 会按 utility 优先级注册, 不循环
keyframes.<动作键>.duration_ticksint否20≥ 1时间轴的总时长 (tick). 小于 1 时整条时间轴会被丢弃并打告警; 循环动画把这个值当作环绕点
keyframes.<动作键>.loopboolean否标准动作取该动作的内置值 (idle/walk/run 为 true, 其余为 false); 非标准动作键为 falsetrue / false是否循环播放
keyframes.<动作键>.prioritystring否标准动作取该动作的内置优先级; 非标准动作键为 utilityambient / utility / action / reactive / terminal (大小写不敏感)播放的优先级; 认不出来的取值按 ambient 处理
keyframes.<动作键>.conflictstring否replacereplace / reject (大小写不敏感)同优先级冲突时的处理策略; 认不出来的取值按 replace 处理
keyframes.<动作键>.frameslist否[]元素为 {tick, action, label} 映射帧的列表. 帧按列表顺序执行, 不会排序; 缺 tick 或者 tick 不是数字的帧会被丢弃, 并打告警 (loader.model_keyframe_missing_tick)
keyframes.<动作键>.frames[].tickint是 (帧内)无≥ 0 (tick)在哪个 tick 触发; tick: 0 会在动画开始时立刻执行.不会把它截断到 duration_ticks 之内 -- 如果某帧的 tick 比时长还大, 播放会一直等到那个 tick 才继续/收尾
keyframes.<动作键>.frames[].actionstring否""一行 CoreLib 动作管道这一帧要执行什么; 空串的帧只通知监听者, 不执行动作, 编译失败会在控制台打告警
keyframes.<动作键>.frames[].labelstring否""—帧的标签, 会随帧通知传给动画监听者 (诊断用)
lod.near / lod.mid / lod.fardouble否16.0 / 32.0 / 48.0—这只生物的 LOD 档位边界, 会覆盖全局 config.yml 的 model.lod; 只写其中几个时, 没写的项按左侧默认值补齐 (不继承全局值)
  • model: 节可以整节都不写; 不写的话这只生物就不挂载模型
  • model.api 与 model.lod 按生物生效: 后端桥按 api 的取值解析并重复使用, LOD 档位按这只生物自己的边界判定; 没写 api 时继承全局 model.api, 没写 lod 时继承全局 model.lod

标准动作 ​

动作触发时机默认优先级循环
idle挂载之后 / 瞬时动作播完回落 / 静止时ambient是
walk水平速度 ≥ walk_speed_thresholdambient是
run水平速度 ≥ run_speed_thresholdambient是
attack攻击命中 (on_damage_give)action否
skill技能释放 (经 mob_play_animation 触发)action否
interact交互 (经 mob_play_animation 触发)utility否
hurt受伤 (on_damage_take)reactive否
death死亡 (on_death) 时, 播完再延迟卸下terminal否

优先级规则: 高优先级的动作抢占当前正在播的; 同优先级按 conflict 的策略替换或拒绝; 低优先级的请求被拒绝. terminal (death) 不会被抢占. 没有定义时间轴的标准动作, 用默认时长 (20 tick) 和该动作内置的优先级/循环设置

关键帧 (K帧) ​

K帧时间轴由 EmakiCoreLib 的动画调度器驱动: 动画开始播放时, tick: 0 的帧立刻执行, 后面的帧在对应的 tick 上, 于实体所属线程精确触发. 帧载荷就是一行 CoreLib 动作管道 (已注册的段落都能写, 比如 spawn_particle, play_sound, 属性修改, 状态切换), 所以动作组合和表达式占位符直接沿用全系管道语法

动作段 ​

在任意 CoreLib 动作行里 (技能, 掉落动作, 第三方插件) 都可以写这三段:

text
self | mob_play_animation animation=spin
self | mob_stop_animation animation=spin
self | mob_set_model blueprint=bone_lord_phase2
段落参数类型必填默认值说明
mob_play_animationanimationstring是无生物 model.animations / model.keyframes 里定义过的动作键; 缺失或者空白时按配置错误返回
mob_stop_animationanimationstring是无含义同上; 用来停止对应定义的播放
mob_set_modelblueprintstring是无新蓝图的名字; 缺失或者空白时按配置错误返回, 后端找不到这个蓝图时会打告警并保持原模型
  • 这三个段落都要求目标能解析成受管生物实体; 目标不是受管生物时返回 skipped, 不报错
  • mob_set_model 支持运行时热切换蓝图 (沿用这只生物定义里的 scale), 切换后会自动回到 idle

第三方插件扩展 ​

其他插件可以通过 EmakiCoreLibApi 注册自定义动画定义, 播放和监听 (见 CoreLib 动画系统). EmakiMobs 的动画调度也会读这张注册表, 所以第三方注册的 mob:<id>:<key> 定义可以被 mob_play_animation 直接引用

故障排查 ​

现象检查
生物没有模型先看后端插件装了没有; model.api (全局或生物级) 是否指向已安装的后端; 启动日志里有没有出现 未找到可用的模型后端 (auto 且两个后端都不可用) 或者 模型后端 '<名称>' 未安装
出现蓝图缺失的告警看有没有 console.model_blueprint_missing; 蓝图名和后端 blueprints/ 里的文件名 (去掉后缀) 是否一致; 后端有没有执行过 /meg reload 或者重启
动画不播放引擎动画名在蓝图里存不存在; animations: 映射里的动作键写对没有
K帧不触发frames[].action 是不是合法的动作行 (编译失败会打 Animation keyframe line did not compile 告警); frames[].tick 有没有按升序写 (帧是按列表顺序执行的, 不会排序); tick 是不是写成了比 duration_ticks 还大的值 (不会截断)
距离远时模型消失这是 LOD 的设计行为; 分界点是 lod.mid, 不是 lod.far, 先把 lod.mid 调大, 需要时再调大 lod.far (早退上界) 和 view_distance (NEAR/MID 档视距). 如果只有某只生物这样, 检查它 model.lod 的覆盖值