人形存档、编辑器与涂绘运行时
角色创建范围、外观持久化、紧凑数据包、涂绘存储与诊断命令。
角色创建、已保存外观和涂绘共用由服务器决定的外观状态。本参考说明其内部持久化、编辑器授权与网络约定。
它做什么
本页说明角色创建、已保存外观和部件涂绘的实现约定。架构介绍状态归属与修改入口,预设数据列出全部外观范围和 JSON 字段,部件资源说明渲染输入。这些都是内部约定,并非公开的人形外观门面。
运行时模型
外观归属与创建阶段
玩家组件保存当前外观、创建阶段、修订号,以及最多 8 套已保存外观。组件 ID 为 isekaiexpansion:humanoid_appearance,重生采用 ALWAYS_COPY。外观发生变化时增加修订号,并由服务端同步;赋予相同外观不产生操作。身高或是否具有身体部件发生变化时重新计算尺寸。已保存外观仅发给所有者;当前外观、修订号和阶段也发给观察者。
创建通常按 BASE → TRAIT → COMPLETE 推进。先提交基础外观;起源选择不再处于等待状态后才进入特征创建。完整的 CREATION 会完成两个步骤。显式重置回到 BASE。提交非创建范围不会推进阶段。
打开编辑器会替换玩家现有授权,使用单调时钟计算固定的 15 分钟有效期。提交既不续期,也不消耗授权;断线会关闭授权。授权允许自身范围,只有 CREATION 允许所有范围。无效范围序号解码为 WARDROBE。
| 范围 | 服务端合并 | 编辑器章节 |
|---|---|---|
CREATION | 采用整个提交外观,再进行校验。 | PRESET BODY FACE HAIR TRAIT OUTFIT UNDERWEAR ACCESSORY PAINT IDENTITY |
CREATION_BASE | 以提交外观为基础,特征引用整体换成当前外观的;当前外观中为空的特征槽位,合并后也为空。 | IDENTITY PRESET BODY FACE HAIR UNDERWEAR OUTFIT ACCESSORY PAINT |
CREATION_TRAIT | 以当前部件为基础,特征引用整体换成提交外观的;调色板不变。 | TRAIT |
APPEARANCE | 采用提交的调色板、面部参数,以及头发、面部、特征引用。 | PRESET FACE HAIR TRAIT PAINT |
WARDROBE | 采用提交的服装、内衣和饰品引用;调色板不变。 | OUTFIT UNDERWEAR ACCESSORY PAINT |
IDENTITY | 字面或预设姓名、昵称开关、性别和年龄。 | IDENTITY |
在范围所属的槽位类别内,合并直接整体替换引用:来源外观里为空的槽位,合并后也为空。其他类别的槽位从不读取提交内容。换装覆盖用来清空槽位的显式清空引用 isekaiexpansion:cleared 不是目录部件,提交中出现它时按任意未知引用处理。随后的校验会补回起源特征,并让每条部件链要么完整、要么不存在。章节是否可见不会改变服务端合并规则:例如衣柜中的颜色编辑不会复制调色板。
当前访问限制:RequestHumanoidScreenPacket 将 CREATION 请求交给待完成创建流程,但对其他请求范围直接授权,不检查权限或创建阶段。范围约束的是提交合并,并不能作为特权编辑的访问控制边界。无效或过期提交只会重新校验现有外观;外观未变时不一定发送纠正同步。
服务负责解析实际起源、校验目录兼容性、移除不可用部件及未知涂绘引用,并补齐首次创建默认值。目录为空时保留部件引用。移除不可用部件后,目录回退可能重新补齐必需槽位;不能把中间的移除步骤理解为所有回退项都符合解锁条件。直接调用内部赋值会绕过这条处理流程。
保存槽位与界面交接
槽位索引为 0–7。保存到较后的索引时,用默认外观补齐间隔;清空操作以默认外观替换槽位,不移除索引。保存和清空请求不要求编辑授权。应用已保存槽位则要求完整的 CREATION 授权,并通过该范围提交,因而会完成创建。
客户端只保留最新待处理编辑授权,连续 3 个无界面 tick 后才打开。暂存界面使用 AFTER_CHARACTER_BASE 或 AFTER_CHARACTER_COMPLETE 门槛;已就绪的暂存界面优先于待处理授权。即使门槛未满足,暂存界面也会在 600 个有效轮询 tick 后放行。已有界面会暂停轮询,因此这不是现实时间超时。空闲看门狗每 60 tick 按条件请求未完成创建;恢复命运界面也需要 60 个安静 tick。
ModernUI 编辑器不会暂停世界。首次创建禁止正常关闭。独立编辑会话保留 48 个撤销状态。更改性别时应用兼容默认项;更换部件 ID 会重置样式和涂绘,ID 相同则保留,仅切换样式也保留涂绘。选择链式部件会穿上整条链,替换或移除其中一个成员会卸下其他成员。确认操作先上传本地可用且被引用的涂绘,再发送外观,随后立即关闭,不等待服务端确认。
预设图库卡片不执行预设解锁元数据。部件卡片依据性别锁定、起源、资源、依赖和解锁规则显示,先列出面向角色性别或通用的部件,链式部件的预览会显示整条链;客户端进度检查无法确认服务端已经授予的进度。最终以服务端校验为准。
姓名浏览器选择可翻译全名ID,提交时由服务器检查新选择是否存在于目录中,最多创建8个结果控件。紧凑重置按钮分别恢复数值默认值、适用部件、当前颜色通道或空白的账号名显示状态,均支持撤销与重做。选择和持久化约定见命名API。
约定
NBT 与网络格式
以下键用于存档,不是数据包 JSON。外观构造器会按预设数据中的范围规范化身份、体型、面部、调色板和部件引用。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
组件 Profile | compound | 默认外观 | 当前外观。 |
组件 Saved | compound list | 空 | 最多读取 8 套外观。 |
组件 CreationStage | int | BASE | 枚举序号;无效值回退为 BASE。 |
组件 Revision | int | 0 | 变更计数;没有范围限制或溢出处理。 |
外观 Version | int | 1 | 最小为 1;接受更高版本,但不按版本切换格式。 |
外观 Identity | compound | 默认身份 | Nickname字符串、可省略的PresetName标识符字符串、UseNickname布尔值、Gender字符串、Age整数。默认依次为空、缺省、false、female、18;昵称上限48个UTF-16单位,预设ID上限256,年龄范围12–400。预设姓名会清空字面昵称。 |
外观 Build | compound | 默认体型 | 浮点键 Height、TorsoWidth、ArmLength、ArmThickness、LegLength、LegThickness、HeadScale、ChestSize、ChestLift、ChestSpread。身高默认 1.8,抬升和间距默认 0,其余默认 1。 |
外观 Face | compound | 默认面部 | 浮点键 EyeSpacing、EyeHeight、EyeDepth、EyeScale、EyeTilt;缩放默认 1,其余默认 0。 |
外观 Palette | compound | 通道默认值 | Channels 为颜色枚举顺序的 int 数组,仅保留 RGB。短数组的缺失项沿用默认值,多余项忽略。缺失或类型错误时使用默认值。 |
外观 Parts | compound list | 空 | 条目包含 Slot 字符串和 Ref compound。未知槽位或错误引用类型跳过;重复槽位以后面的值覆盖前面的值。 |
部件 Ref | compound | 无引用 | 必须有合法的 Part 标识符字符串,否则移除引用。Style 默认 default;可选 Paint 必须是 32 位十六进制字符,规范化为小写,无效时丢弃。 |
外观 Origin | string | 无 | 无效标识符视为缺失;玩家校验时以实际起源替换。 |
样式名会去除首尾空白、转为小写,最多 64 字符,仅允许 ASCII 字母、数字、下划线和连字符;无效时改为 default。存档调色板顺序与槽位序号涉及兼容性。
共享编解码器先写版本 VarInt,再写章节字节。位值 1、2、4、8、16、32 分别选择身份、体型、面部、调色板、部件和起源。省略章节使用默认值。读取器不按版本分支,也不消费未知章节位对应的数据;两端必须使用一致格式。
| 章节 | 数据 |
|---|---|
| 身份 | 标志字节:1昵称,2启用昵称,4与默认性别相反,8年龄,16预设姓名。按标志依次写入昵称字符串、年龄VarInt、预设ID字符串;两种字符串上限分别为48和256。 |
| 体型 | 稀疏 VarInt 位掩码及浮点值,顺序为 Height TorsoWidth ArmLength ArmThickness LegLength LegThickness HeadScale ChestSize ChestLift ChestSpread。 |
| 面部 | 稀疏 VarInt 位掩码及浮点值,顺序为 EyeSpacing EyeHeight EyeDepth EyeScale EyeTilt。 |
| 调色板 | 按颜色枚举顺序排列的 VarInt 位掩码;每个存在的 RGB 值占 3 字节。 |
| 部件 | VarInt 条目数,随后为槽位无符号字节及标志。标志 1/2 省略默认命名空间或槽位路径前缀;4/8 包含样式或涂绘。字符串上限:命名空间 64、路径 192、样式 64、涂绘 32。无效槽位序号解析为 BODY;读取器不限制条目数。 |
| 起源 | 标识符字符串,最多 128 字符。 |
组件同步在外观后追加修订号 VarInt、创建阶段字节和所有者布尔值。只有所有者继续接收保存数量及外观。NPC 外观追踪复用此紧凑外观编解码器。
涂绘编辑器与二进制格式
涂绘是部件纹理上的透明覆盖层,在染色之后合成,无法在原图 alpha 覆盖范围之外增加可见像素。编辑器复制现有涂绘,或按源纹理创建画布,每个维度最大 256;尺寸不可用时使用 64 × 64。空白涂绘会清空引用。非空涂绘先缓存到本地,并在上传前以内容 ID 引用。
工具包括画笔、橡皮、直线、矩形、椭圆、填充和取色。画布历史保留 32 个状态,重新绑定时清空。画笔宽度为 1–32 像素,半径为宽度的一半(宽度 1 时为 0.5),硬度 0–1,不透明度 0.02–1。缩放为适配尺寸的 1–32 倍,滚轮步长乘以 1.25。镜像坐标为 width - 1 - x。填充精确匹配 ARGB,橡皮减去 alpha。单次手势按最大覆盖量处理,避免同一像素重复加深。取色时只要覆盖层 alpha 非零就返回其 RGB,否则返回源图 RGB;不会采样最终合成颜色。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| 魔数 | 4-byte int | 0x49535054 | 大端二进制签名。 |
| 格式版本 | byte | 1 | 当前涂绘编码。 |
| 宽 / 高 | 2 unsigned shorts | 无 | 每个维度必须为 1–256;加上签名和版本,头部共 9 字节。 |
| 像素数据 | compressed bytes | 无 | Deflate 压缩的大端 ARGB 整数;接受的编码文件最大 96 KiB。 |
| 内容 ID | string | 无 | 仅对原始像素字节计算 SHA-256,取前 32 个十六进制字符;尺寸不参与哈希。 |
编码器本身不执行编码大小上限检查,包装和解码步骤才执行。解码要求解压字节数符合预期,但不要求 inflater 已完成,也不拒绝所有可能的尾随字节。尺寸不同但展开像素相同的画布可能共享 ID;已有 ID 会保留最先存入的编码数据。
涂绘传输与存储
分块携带 ID、总字节数、总块数、块索引和数据。总字节数必须大于零且不超过 96 KiB;数据为 1–16 KiB;块数为 1–7,索引必须在该数量内。写入端在大小上限处最多只需要 6 块。读取端不要求块数等于字节数向上取整的计算结果。多块偏移使用 index × 16 KiB;重复块替换数据但不增加已收数量。单块完成使用实际数据,不核对声明总字节数。完成后解码并验证内容 ID。
每个传输累积器最多容纳 8 个未完成项目,再启动一个会清空全部未完成项目。没有分块超时机制。断线会清除该玩家的上传累积器。上传和读取请求不检查编辑范围或所有权:涂绘存储是共享的,不是玩家私有数据。
持久状态键为 isekaiexpansion/humanoid/paint_v1,由 IsekaiPersistData.key("humanoid", "paint", 1) 提供,使用服务端主世界管理器。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
Entries | compound list | 空 | 保存的涂绘记录。 |
Id | string | 空 | 加载时跳过空 ID。 |
Data | byte array | 空 | 跳过空数组或超过 96 KiB 的数组;加载时不解码,也不校验哈希。 |
Used | long | 0 | 基于现实 UTC 时间的最后使用 epoch day,与世界时间无关。 |
新插入导致超过 8192 个文件或 48 MiB 时,按最早使用日淘汰。已有 ID 保留原始字节并刷新使用日。启动时删除超过 60 天的条目,没有每日 tick 清理。访问会刷新使用日,但已保存外观不会永久保留其涂绘。加载不执行配额限制;重复 ID 会替换映射中的值,但每条记录仍会增加字节累计量。
客户端磁盘文件位于游戏运行目录的 isekaiexpansion/humanoid_paint/<id>.ispt,读取时校验哈希。内存缓存上限为 256 项,到达上限时整体清空。未知请求在 5 秒后重试;明确的缺失响应会记住,直到收到有效数据或断线。断线清除待处理、缺失和传输状态,但保留已加载内存数据及磁盘文件。
合成纹理
合成纹理缓存目标为 384 项,按访问顺序淘汰。键包含基础纹理、遮罩、绑定 RGB 值和涂绘。合成在工作线程执行,GPU 上传在渲染线程执行。新颜色结果尚未就绪时,渲染器可使用同一基础纹理、遮罩、涂绘组合的上次就绪纹理,或基础纹理;该回退组合刻意不包含颜色。
涂绘修订会使带涂绘的条目失效;资源重载会清空缓存。旧任务上传前必须仍对应原条目,否则关闭其图像。修改合成逻辑时,应保留资源归属和渲染线程上传约定。
NPC 通过 HumanoidBoneShaper.finishAnimatedPose 完成控制器驱动的姿态。死亡和使用物品时也会应用身份体型,随后只清除变换修改标记,保留当前渲染变换。这样下一次控制器更新不会累积自定义偏移或缩放,同帧再次绘制时也能沿用已完成的姿态。
NPC移动动画由异界扩展的NpcAnimationController和共享Gecko套件负责。实体文件按片段覆盖,独特角色同样可使用基础回退,详见NPC资源。市民、冒险者和独特NPC均使用公共跟随任务。Better Animations兄弟项目仅为isekaiexpansion:simple_clone接入玩家移动动画,NPC不再加入该动画层。
NpcModelBones为渲染器分别保存NPC、MORPH、FIRST_PERSON的可变骨骼。骨骼从建模初始变换复制,共享方块几何;资源重载替换烘焙源后,私有骨骼也重新创建。玩家显示层、NPC世界姿态和第一人称变身手臂互不覆盖。同帧重复绘制保留已完成姿态,不在GeckoLib跳过重复更新之前清空它。
HumanoidPlayerPoseBridge仍将匹配的变身显示实体映射到其宿主玩家的姿态,包含外层身体与手持物品通道。自主NPC只接入自身的Better Combat武器动画或明确设置的预览动画,普通移动使用Gecko。死亡、追踪中的物品使用、表情、POI活动和专属战斗保留自身动作。
服务端运行NPC移动和战斗,同步普通实体状态与追踪中的活动状态。客户端逐个读取NPC进行渲染,不读取附近玩家的输入。仍须在游戏中验收移动、第一与第三人称变身、双客户端、中途加入、跨维度和重连,并检查片段回退、资源重载和连续玩家/NPC/变身/手臂姿态隔离。
玩家姿态与手持物品
玩家渲染器保留原版模型和附加层流程。PlayerEntityRendererMixin 在姿态计算后隐藏原版身体几何体,并添加 HumanoidPlayerFeature;骨架接收当前双足模型姿态。HumanoidPlayerPoseBridge.restoreBindPose 在形体变换前恢复初始偏移、旋转和缩放,避免变换逐帧累积。现有盔甲跟随外层身高缩放,但此路径不会按每个肢体滑块重塑盔甲。
对于Player Animator,皮肤替换限定在玩家模型的原生绘制范围内。HumanoidFirstPersonPartMixin在每只手臂的ModelPart.render调用处替换几何,此时外层模型已应用身体弯曲。该范围内不再绘制原版皮肤袖层。完整模型遍历仍然继续,作用域在finally中恢复;护甲与手持物随后进入原生特征层阶段。Punchy和原版手部绘制继续使用已有手臂入口。
第一人称渲染接收调用者已计算姿态的手臂,并应用 animatedArm.rotate;允许显示在手臂上的部件层跟随身体姿态。运行时渲染失败会在当前客户端进程中禁用 HumanoidFirstPersonArmRenderer。玩家附加层则在失败后单独禁用自身实例。应检查日志中的异常;这两个类都不会在资源重载时清除禁用标志。
HumanoidItemAnchor 只作用于已启用人形身体的玩家。它读取 right_arm 到 main_item、left_arm 到 off_item 的轴心差,应用当前手臂姿态,以手臂粗细和长度缩放定位偏移,再抵消局部缩放并设置物品朝向。它不读取定位骨骼旋转;整体身高已由外层渲染变换负责。
定位信息按身体模型缓存。只有两个身体定位点都无法解析时才尝试共享骨架;若其中一个存在,缺失侧不会单独继承骨架定位点,而会返回普通手持物品路径。因此,仅修改定位骨骼旋转不能修正握持偏移。手持物品附加层还会在绘制前应用玩家当前物品动画变换。
扩展方式
新增字段时同时处理 NBT 键、网络标志和顺序、默认值、构造器规范化、相等判断、视觉失效及通信两端。版本号本身不提供迁移。保持调色板枚举顺序和槽位序号;增加通道前检查位掩码容量。
增加编辑范围时,同时更新授权关系、服务端合并、章节列表和请求权限。明确清空、调色板编辑、应用保存槽位、涂绘上传是否允许;隐藏章节本身无法执行这些规则。
涂绘格式或哈希变更需要同步处理磁盘缓存、持久状态、传输校验和外观引用。若新格式将尺寸纳入内容身份,必须明确旧 ID 的迁移方式。
验证
管理员命令
命令位于 /isekaiexpansion 下(别名 /ise),要求权限等级 2。
| 命令 | 结果 |
|---|---|
/ise humanoid edit [target] | 为执行玩家或选中玩家打开完整创建编辑器,不标记为首次创建。 |
/ise humanoid appearance <target> | 为选中玩家打开外观范围编辑器。 |
/ise humanoid reset <target> | 校验默认外观,重置阶段为 BASE,打开首次完整创建。 |
/ise charactercreate [targets] | 为执行玩家或选中玩家重放首次进入世界时的开场流程。先撤销已确认的命运并收回其效果,清空所有已启用的起源层,并像登录时一样让自动层自行选择;再把角色重置为经过校验、处于 BASE 的首次默认外观,然后授予 CREATION_BASE,起源选择界面排在它之后。特征步骤与命运界面按正常顺序接续,首次进入的粒子登场效果也会重放。 |
/ise humanoid export player <name> [target] [--purge] | 将自己或人形实体导出到 config/isekaiseries/humanoid_presets/<name>.json。 |
/ise humanoid export npc <name> <target> | 将基础 NPC 的基础外观和衣柜导出到 config/isekaiseries/npc_presets/<name>.json。 |
/ise humanoid resync | 重发当前目录并重新校验在线玩家,不重载文件。 |
/ise humanoid status | 显示部件、玩家预设、NPC 预设数量,以及涂绘存储数量和大小。 |
导出名只保留小写 ASCII 字母、数字和下划线,将连字符或空格改为下划线,删除其他字符,最多 48 字符;结果为空时失败。已有文件会被覆盖。--purge移除昵称开关、字面/预设姓名、起源和特征部件,但保留性别与年龄。JSON 导出不包含涂绘,形状参数保留 3 位小数,且存在预设数据所述的服装解锁往返问题。检查导出文件后再复制到数据包;导出目录不是自动目录输入。
分别改变调色板、性别和特征引用,并清空槽位(包括部件链中的一个成员),验证范围合并。单独测试授权过期和应用保存槽位。通过起源选择、重生、重连检查首次创建,并测试暂存界面被其他 UI 打断的情况。由另一玩家观察,确认当前外观同步且未泄露保存槽位。
涂绘需测试本地预览、服务端接收、其他客户端下载、缺失 ID、过大或高噪声文件、重复分块、断线和资源重载。检查染色 alpha、源图透明像素和未完成合成的回退。文档或插件构建成功不能代替这些游戏内验证。