Kzeroko KTM2

表情数据

表情目录、纹理序列帧、动作参数与客户端资源校验。

更新于 2026/9/18 7 分钟阅读

一个表情定义把图片、翻译键和动作组合成贴纸。服务端决定目录与播放请求;客户端用自己的资源包解析图片,因此数据包和图片资源需要配套提供。

文件放在哪里

定义放在data/<namespace>/emojis/<path>.json,表情ID为<namespace>:<path>。图片放在assets/<namespace>/textures/...;定义中的纹理ID保留textures/前缀和扩展名。同ID资源由数据包优先级选择,不合并字段。

最小示例

下面保留内置isekaiexpansion:evelina/smile的必填字段,并使用其已有纹理:

{
  "texture": "isekaiexpansion:textures/gui/emoji/evelina/evelinasmile.png",
  "title_key": "emoji.isekaiexpansion.smile.title",
  "caption_key": "emoji.isekaiexpansion.smile.caption",
  "category_key": "emoji.isekaiexpansion.category.positive"
}

字段

字段类型默认值作用
textureidentifier必填包含textures/和.png的资源包纹理ID。ID语法错误使定义失败,图片缺失由客户端处理。
title_keystring必填非空白标题翻译键;数据加载器不检查译文是否存在。
caption_keystring必填非空白说明翻译键。
category_keystring必填非空白分类翻译键。
orderinteger0显示顺序由小到大,同值按表情ID字符串排序,没有显式范围限制。
duration_ticksinteger70选择器播放时长,70刻(3.5秒);限制在20–200刻(1–10秒)。
frame_widthinteger0每帧像素宽度。负数变为0,0采用整图宽度,正数最多取整图宽度。
frame_heightinteger0每帧像素高度。负数变为0,0采用整图高度,正数最多取整图高度。
frame_countinteger1至少1帧;客户端再限制到纹理中完整网格单元的数量。
frame_time_msinteger80每帧毫秒数,至少1。
loopbooleantrue循环序列帧;false时停在最后一帧。
animationobjectsway_wiggle对象或类型名称字符串。缺失或null使用默认摇摆,字符串使用该类型默认参数。
animation.typeenum(none, sway_wiggle, float_bob, pulse, tremble, bounce, elastic_pop, squash_stretch)sway_wiggle类型名称去除两端空白且不区分大小写,未知值拒绝目录重载。
animation.period_ticksnumber按类型决定周期,以刻为单位,至少1刻(0.05秒);下表同时列出秒数。
animation.offset_pixelsnumber按类型决定移动幅度,单位像素,最小0。
animation.max_scalenumber按类型决定较大缩放参数,最小0.05;不强制要求大于min_scale。
animation.min_scalenumber按类型决定较小缩放参数,最小0.05。
animation.rotation_degreesnumber按类型决定非负旋转幅度,单位度;颤动实际使用的幅度还会限制到4度。
animation.squashnumber按类型决定挤压拉伸参数,限制在0–0.45。
animation.loopbooleantrue独立于序列帧循环,控制图标动作循环;false在周期结束后恢复原始姿态。

动作默认值

所有类型的动作循环默认为true。各列对应上面的动作参数;周期列是刻数及秒数。

类型周期位移最大缩放最小缩放旋转挤压
none30 (1.5秒)01100
sway_wiggle30 (1.5秒)011150
float_bob60 (3秒)41100
pulse28 (1.4秒)01.2100
tremble8 (0.4秒)21130
bounce24 (1.2秒)81100
elastic_pop26 (1.3秒)01.30.8200
squash_stretch24 (1.2秒)91100.18

对话播放选项

isekaiexpansion:emoji 对话动作在动作值内接受以下字段。这些属于播放选项,不是表情贴纸定义中的字段。

字段类型默认值作用
emojiidentifierrequired目录 ID。语法错误会使动作解码失败;未知 ID 不产生播放。
duration_ticksinteger70规范化后至少 1 刻(0.05 秒);默认 70 刻(3.5 秒),独立于定义时长。
priorityinteger50构建播放选项时限制在 0–1000。
policystringreplacereplace、queue 或 force;忽略首尾空白及大小写。未知值采用 replace。
targetstringdialogue_entitydialogue_entity、player 或 both。未知值采用 dialogue_entity。对话实体缺失或不是存活实体类型时跳过该目标;both 仍作用于玩家。
interruptiblebooleantrue允许足够优先级的普通替换;force 不受此标记限制。
interrupt_on_damagebooleantrue允许服务端在受伤时中断最新请求。

可选字段缺失时使用所列默认值;缺少 emoji 或字段类型错误会使动作解码失败。额外字段被忽略。排队与受伤中断约定见表情贴纸播放 API。

完整示例

内置微笑表情把播放时长改为74刻(3.7秒),摇摆周期改为48刻(2.4秒),旋转幅度改为2.5度:

{
  "texture": "isekaiexpansion:textures/gui/emoji/evelina/evelinasmile.png",
  "title_key": "emoji.isekaiexpansion.smile.title",
  "caption_key": "emoji.isekaiexpansion.smile.caption",
  "category_key": "emoji.isekaiexpansion.category.positive",
  "order": 20,
  "duration_ticks": 74,
  "animation": {
    "type": "sway_wiggle",
    "period_ticks": 48,
    "rotation_degrees": 2.5
  }
}

序列帧按从左到右、再从上到下排列。未填帧尺寸时整张图只有一个网格单元;要使用多帧,必须按图片布局填写尺寸。边缘不足一帧的像素不会计入可用帧数。

校验

缺少必填键、空白翻译键、非法纹理ID、错误的已读取字段类型或未知动作类型,会汇总为目录重载错误。目录替换前抛出异常,因此这个定义加载阶段失败时保留原目录。未知字段被忽略,不能用额外字段改变播放优先级或队列策略。空对象缺少必填字段,空白文本不是合法JSON。

时长、帧尺寸、帧数、帧间隔和动作参数按字段表修正,不因有限数值超范围就拒绝目录。数值读取没有精确整数或统一有限数校验;应使用正确类型的有限JSON数值,不依赖小数截断或极大指数的转换。

服务端不验证图片是否存在、尺寸是否正确,也不验证翻译是否存在。客户端找不到或无法解码图片时记录警告,不建立该表情的可用图片定义;其他表情不受影响。

重载

/reload重载服务端目录;玩家加入和数据包重载成功后发送目录给客户端。客户端收到目录后重建图片定义,客户端资源重载也会重建。图片不会随目录数据包传输,需要另行提供资源包。

选择器发送的表情使用定义时长,服务端限制两次发送至少间隔30刻(1.5秒)。其他播放入口可以另给时长,不能把duration_ticks视为所有播放请求的强制寿命。

相关页面

屏幕空间文字绘制可参考伤害数字;实体生命周期表现见实体特效。