模型动画
模型自带动画适合某个模型独有的 idle、walk 和 attack。多个自定义人形或整身时装共用武器动作时,可以使用通用人形动作与游戏内工作室,在游戏里编辑关键帧、骨架映射和连段。下文的自动动画规则适用于未被通用动作接管的模型。
工作室支持直接导入和导出 Blockbench 的标准 .animation.json。人物动作、光环旋转与悬浮物浮动可以放入不同播放组,同时执行;每组选择根骨骼及其子骨骼范围。独立装饰请放在人物部位之外,避免继承人物的旋转。具体操作、骨架兼容与服务器保存见分组动画。
服务端同步动画资源路径、默认动画名和运行操作。客户端从自己的 resourcepacks/ChaEngine/model/、ChaAssets 资源或配置的 HTTP/HTTPS 直链读取动画定义。animation 填写完整网络地址时,直接下载原始动画 JSON;普通相对路径仍从客户端资源目录读取。
使用 Blockbench .bbmodel 时,动画可以和模型保存在同一个工程中,不必填写独立的 animation 路径。客户端读取 position、rotation、scale 数值轨道,并将曲线关键帧按 20 Hz 归一化;表达式和事件轨道需要先烘焙为数值关键帧。
Geo 表达式动画
.geo.json 配合独立 .animation.json 播放模型自带动画时,可以使用随动画时间变化的旋转,以及通过缩放显示、隐藏骨骼实现的贴图换帧。例如,云层特效可以一边绕中心旋转,一边依次显示不同贴图帧。原动画中的 query.anim_time 时间查询和 math.floor、math.mod 条件换帧会在播放时计算,不需要为这种效果手工补出大量数值关键帧。
NeoForge 1.21.8 的早期客户端构建曾让这类动画反复回到初始姿态,或让多个载体的动画互相影响。遇到“Blockbench 中连续旋转,游戏中停住或跳动”时,请更新对应客户端并完全退出、重启游戏,再用原模型、原贴图和原动画对照相同的动画名称。此修复不需要更改服务端配置或模型资源。
NeoForge 1.21.8 和 1.21.11 的部分构建还会让三元表达式(条件 ? 成立时的值 : 不成立时的值)控制的贴图换帧停在首帧,表现为武器颜色或光效不再变化,即使同屏云层仍在旋转。请更新包含条件换帧修复的客户端,保留原始公式和资源,无需为了恢复贴图动画而让武器本体旋转或修改循环设置。这里的光效指模型动画中的贴图效果,不表示模型会自动照亮周围方块。
早期条件换帧修复包曾出现修复未生效的情况。同一版本号可能对应多轮构建,请按交付文件大小或 SHA-256 核对实际安装包,替换后完全重启游戏;帧率恢复并不代表贴图换帧也已恢复。
同屏的多个模型分别保存动画名称、播放进度和叠加动画状态,模型与贴图资源仍共享缓存。云层与时装、武器一起显示时,切换其中一个模型的动画不应重置其他模型;即使多个载体使用同一份模型资源,也应独立播放。早期构建仍有共用播放状态的问题,遇到隐藏时装后云层才恢复、模型相互串动画等现象,请更新所用版本的客户端并完全重启游戏。
动画隔离更新后的部分构建曾在反复绘制三维物品或生成、移除特效时积累播放状态,造成卡顿。性能修复会复用同一物品的播放进度,并释放已失去载体引用的状态;这项修复不需要更改动画文件或服务端配置。如果单人正常、进服后未释放技能便立即掉帧,还需使用包含模型匹配性能修复的客户端。该修复保留动画逐帧插值;请按动画与帧率排查区分基础帧率与技能生成后的额外开销。
以上说明适用于模型自带的独立 Geo 动画,不改变 .bbmodel 内嵌动画或动作工作室导入的支持范围;也不表示所有依赖特定游戏状态的 Blockbench 表达式都能直接使用。
零厚度 Geo 平面
一些 .geo.json 模型会把一个轴的 size 写成 0,用一张纸片贴图表现冰面、光环或技能特效。ChaEngine 会自动兼容这种写法:保留原来的 UV、骨骼和动画,并为同一位置、尺寸相同的动画平面安排稳定的微小层次,避免多个平面在游戏里闪烁。不需要为了显示效果手动把模型改成立方体,也不需要新增配置。
这个处理只针对单个模型内部的零厚度平面。模型中若有多个本来就有厚度、且位置完全重合的部件,仍应在 Blockbench 中调整位置或厚度;多个实体之间的模型重叠也需要调整摆放位置。替换客户端模组后请完全重启客户端,再从正面和斜角观察悬空模型以及动画切换过程。
完整示例
一个可供方块或物品使用的配置片段:
animated_crystal:
model: "crystal/crystal.geo.json"
animation: "crystal/crystal.animation.json" # 客户端动画文件
texture: "crystal/crystal.png"
default-animation: "idle" # 文件中实际存在的动画 ID
scale: 1.0
position: [0, 0, 0]
rotation: [0, 0, 0]
collision: [1, 1, 1]实体与时装没有 default-animation 配置,它们按实体状态从动画文件选择名称。
模型、贴图与动画可以分别使用网络地址或本地路径。网络动画在首次使用时后台下载;下载期间模型可能先静态显示,完成后在资源刷新时开始播放。动画地址必须返回 JSON 文件内容,查询参数和 token 会保留;需要登录的分享页不能代替直链。完整网络配置、失败重试和缓存刷新方式见HTTP/HTTPS 网络资源。
动画类型
方块默认动画与特殊动画
方块首次渲染时使用 default-animation。以下命令建立或停止特殊动画状态:
/chaengine block animation play <location> <animation>
/chaengine block animation stop <location>再次播放会直接替换旧名称。执行停止后,该方块进入显式无动画状态,不会立刻回到默认动画。断开世界、资源代次变化或动画状态整体清理后,下一次渲染才重新以配置默认值开始。
方块动画目标由维度和方块位置定位,但模型 ID 始终从方块实体自己的数据读取,不存在坐标到模型 ID 的映射。
物品默认动画
未填写 item-texture、直接渲染三维模型的物品可以播放 default-animation。物品没有服务端“播放一次特殊动画”的公开操作。填写 item-texture 后改用静态平面物品渲染,模型动画字段不参与显示。
实体自动状态动画
客户端按以下优先顺序判断当前状态:死亡、攻击、受伤、使用、游泳、潜行、空中、奔跑、移动、空闲。每种状态依次寻找这些候选名称:
| 状态 | 候选动画 ID |
|---|---|
| 空闲 | idle、animation.idle |
| 移动 | move、walk、walking、animation.move、animation.walk |
| 奔跑 | run、running、sprint、animation.run |
| 攻击 | attack、attacking、swing、animation.attack |
| 受伤 | hurt、hit、damage、animation.hurt |
| 死亡 | death、die、dead、animation.death |
| 空中 | jump、fall、air、animation.jump |
| 游泳 | swim、swimming、animation.swim |
| 潜行 | sneak、crouch、animation.sneak |
| 使用 | use、cast、skill、animation.use |
匹配忽略大小写,并接受完整名称以 .候选名、_候选名 或 /候选名 结尾。当前状态找不到可用动画时,再尝试 idle。
玩家时装同样跟随穿戴者状态选择动画,因此装备配置只需要提供 animation 路径,不配置默认名称。
服务端触发的实体特殊动画
对有效实体执行以下命令后,指定名称会覆盖自动状态动画:
/chaengine entity animation play <entity> <animation>
/chaengine entity animation stop <entity>再次播放会替换当前覆盖。执行停止后删除覆盖,立即恢复自动状态选择。
服务端只验证实体有效且名称非空,不会读取客户端动画文件。名称拼写错误时操作仍可能返回成功,但客户端没有可播放内容。
在 MythicMobs 技能中播放
安装 MythicMobs 后,ChaEngine 会注册 chaengineanimation mechanic,并继续使用同一个服务端 Jar。当前 API 编译兼容基线包括 MythicMobs 4.11.1,以及 MythicMobs 5.6.2、5.11.2 与 5.13.0。Minecraft 1.16.5 使用 4.11.1;MythicMobs 5.7 起不再支持 1.16 系列,较新环境使用对应的 5.x 版本。没有安装 MythicMobs 时只是不注册这个 mechanic,其他模型能力不受影响。
- chaengineanimation{id=animation.slime_common.attack;duration=20} @self| 参数 | 别名 | 默认值 | 说明 |
|---|---|---|---|
id | i | 无 | 必填;动画文件中的完整动画 ID,可使用 MythicMobs 占位符 |
duration | d | 20 | 可使用 MythicMobs 占位符;必须大于 0,单位为服务端 tick |
@self 可以换成 @target 或其他实体目标器;不写目标器时使用施法者。集合目标器会为每个目标分别计时。
同一实体再次执行时,新动画会立即替换旧动画并重新计时。时间结束后恢复 ChaEngine 的实体自动状态动画。实体死亡、MythicMobs despawn、区块卸载、玩家退出或 ChaEngine 关闭时,未结束的计时都会清理;旧计时不会停止后来由命令、Java API 或新技能播放的动画。
mechanic 固定静默执行,不派发命令、不发送玩家消息,也没有 replace 或 silent 参数。配置加载错误和不受支持的 MythicMobs 版本仍会在控制台给出诊断。
服务端只检查 id 非空,不能确认客户端是否真的拥有该动画 ID。没有画面时请检查客户端动画文件和完整 ID。真实 ID 写作 animation.slime_common.attack,不要把 Markdown 显示时可能出现的反斜杠写进下划线前。
实体覆盖动画
覆盖动画使用独立动画层,不会替换基础的移动、空闲或普通特殊动画。它适合在实体仍保持行走姿态时叠加受击、施法、挥手等局部动作。
覆盖动画通过 Java API 控制:
playCarrierEntityOverlayAnimation(entity, animationName)播放或重新开始指定覆盖动画;stopCarrierEntityOverlayAnimation(entity)停止覆盖层,基础动画继续按原状态运行。
同一实体同时只保留一个服务端覆盖动画;再次播放会替换并重新开始。名称仍必须存在于客户端动画文件中,服务端不会校验资源内容。普通的实体动画命令控制基础覆盖状态,不等同于这层叠加能力。
每个独立受伤周期开始时,客户端都会将自动受伤候选动画(例如 hit)重新播放一次;同一受伤周期持续期间不会逐帧重置。该行为属于客户端自动状态,不需要服务端额外调用覆盖动画 API。
事件与顺序
服务端提供实体特殊动画开始、结束事件,普通特殊动画和 API 触发的覆盖动画共用这两个事件类型:
- 开始事件在发送播放操作前触发,包含实体和本次动画名。
- 结束事件在发送停止操作前触发,包含实体和服务端最后记录的动画名;此前没有记录时为
null。 - 连续两次播放会触发两次开始事件,后一动画替换前一动画,但不会自动补发前一动画的结束事件。
- 客户端动画自然播完不会回传服务端,因此不会自动触发结束事件。
方块动画目前没有对应的公开 Bukkit 开始/结束事件。API 用法见Java API。
运行规则
- 独立
animation为空时,模型按静态方式渲染;.bbmodel仍会读取工程内动画。 default-animation只属于方块和物品配置。- OBJ 是静态网格,即使填写动画字段也会忽略并记录一次警告。
.bbmodel的动画名称来自工程内动画列表;default-animation和实体状态候选名称的选择规则不变。- 资源更新、ChaAssets 授权撤销或玩家断开会清理客户端动画状态和相关缓存。
- 动画名必须与客户端文件实际 ID 对应;服务端不会替客户端纠正名称。
- 覆盖动画使用独立控制层;停止覆盖动画不会停止基础动画。
常见问题
实体一直播放 idle:确认状态动画 ID 属于上表候选,或使用能以候选名结尾的完整 ID。
方块停止后没有恢复 idle:这是显式停止语义。需要恢复时再次播放 idle,或让客户端重新建立动画状态。
服务端返回成功但没有动画:返回值只说明目标和输入可发送;检查客户端动画文件与动画 ID。
覆盖动画播放后走路停了:确认业务调用的是 playCarrierEntityOverlayAnimation,而不是会替换基础状态的 playCarrierEntityAnimation。
时装模型静止:确认装备配置包含有效 animation 文件,并至少提供 idle 或 animation.idle。
物品动画不显示:填写 item-texture 时使用的是平面贴图路径;删除该字段才渲染带动画的三维模型。
猹件开发组