变身生命周期与服务端运行时
权威阶段、合成形态归属、持久化、能力输入、移动和乘客约定。
变身将服务端管理的形态会话、客户端表现与可选种类控制器组合起来。本页沿着进入、持久化、输入与清理流程说明各部分的约定。
它做什么
变身保留玩家作为世界中的真实实体,同时借用生物实体的表现、尺寸和部分行为。MorphComponent 管理权威阶段与形态身份。MorphEntityFactory 创建不会生成到世界中的生物实体,并禁用生物 AI;它不是拥有独立库存或常规世界 tick 的第二个角色。
能力和属性编写见变身数据。当前公开的服务端入口是 api.morph.MorphService,下文内部控制器属于实现细节。
运行时模型
阶段与时长
| 阶段 | 组件表现/尺寸判定 | 服务端推进 |
|---|---|---|
NONE | 玩家身体。 | 不处理激活形态。 |
ENTERING | 过渡进度达到 0.5 后采用形态。 | 经过 transitionTicks 后进入 ACTIVE。 |
ACTIVE | 形态身体。 | 执行姿态、特性和已注册形态 tick,可能到期。 |
EXITING | 进度低于 0.5 时采用形态,之后采用玩家。 | 经过 transitionTicks 后清空。 |
过渡最少 4 tick,通常为 18。阶段变化会记录世界时间、增加修订号、使形态缓存失效、重算尺寸并同步,然后广播 ON_MORPH_PHASE_CHANGE。前后阶段相同不发出事件。接收 NBT 时阶段变化也会广播,因此监听器施加游戏逻辑前必须检查逻辑侧。
组件的视觉判定使用插值进度,尺寸判定使用 tick delta 0。服务端还在 transitionTicks / 2 时额外重算,采用整数除法。奇数过渡长度可能使这次显式刷新早于 0.5 阈值;尺寸验证应包含奇数长度,不能假定中点完全一致。
时长 0 表示无限。正时长从进入 ACTIVE 起计算,进入和退出不占用该预算。到期时等待可容纳站立玩家的空间;受阻时继续重试,但只发送一次到期受阻消息。剩余时间由 phaseStartedTick 推导,不是保存的倒计时。玩家断线期间该世界推进的时间仍影响截止点,并不会在离线时暂停。
正常退出会停用特殊移动、弹出受支持乘客、分离形态运行时状态,再开始返回过渡。endImmediately 同样执行移动与乘客清理,但直接清空,不单独播放退出过渡。单独调用底层 clear 不等于完整清理入口。
实际渲染模型由客户端表现控制器根据粒子覆盖决定,不直接采用本表中的组件判定。
进入与身份变化
已有形态时,只有来源执行 ID 与请求的变身能力一致,toggle 才会返回;其他能力被拒绝。进入要求玩家未骑乘、类型能创建生物实体,且空间容纳目标尺寸。正常返回检查站立玩家空间。
底层 MorphService.morph 本身不会拒绝已激活形态,调用者必须决定替换策略。MorphFormRequest.start 额外拒绝已有变身。开发命令调用底层方法,因此能够替换形态。
若形态来源是已注册的 MorphingTriggerableSkill 执行,而玩家不再持有它,MorphIdentityReconciler 会立即结束形态。查询包含当前未激活的已持有能力。程序化授予等非能力来源保留。起源选择和成长变化会调用此协调逻辑,并非每 tick 扫描所有权。
形态归属与 tick
组件修订号或世界变化时重建缓存形态。绑定记录宿主,并向形态暴露只包含宿主的合成乘客列表;不会让真实玩家骑上未生成的形态。旋转快照在本地重建前后保留当前和上一帧的 yaw、pitch、身体与头部角度。
普通状态同步复制宿主位置、速度、流体状态、姿态、冲刺和潜行、静音、按比例生命值、年龄、肢体动画、挥手、受伤和死亡状态,以及手持栈。手持栈是复制,不是转移。原生旋转处理器可保留自身旋转,并将身体 yaw 传回宿主。上一帧旋转在宿主 tick 入口、移动前推进,不能以完整实体 tick 代替这条桥接。
MorphRiderContext 仅在有作用域的原生调用中提供可嵌套线程局部驾驶者,关闭时恢复先前上下文。生成的能力实体可从已注册身份解析器获得 MorphAbilityOrigin,包含宿主 UUID、形态类型和原生能力 ID。此归因不同于给实体添加真实骑乘者或改变世界归属。
约定
持久化与同步状态
组件 ID 为 isekaiexpansion:morph 和 isekaiexpansion:morph_variant。变身状态重生使用 NEVER_COPY,变体选择使用 ALWAYS_COPY。重连可重建保存形态,重生则不保留之前的变身。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
phase | string | NONE | 严格枚举名,无效或缺失时为 NONE。 |
entityType | 标识符字符串 | 无 | 形态类型,非法语法变为 null。 |
sourceSkill | 标识符字符串 | 无 | 来源执行或程序化授予 ID,语法处理同上。 |
primaryAbility | 标识符字符串 | 无 | 实体覆盖之前的主槽位 ID。 |
secondaryAbility | 标识符字符串 | 无 | 实体覆盖之前的副槽位 ID。 |
skin | 标识符字符串 | 无 | 可选专用纹理选择器。 |
entityNbt | compound | {} | 复制的表现 NBT,构建形态时进行清理。 |
phaseStartedTick | long | 0 | 阶段变化时的当前世界绝对时间。 |
transitionTicks | int | 读取时为 4 | 读取器最小限制为 4;新构建组件初值为 18。 |
durationTicks | int | 0 | 限制为非负,0 表示无限;仅计算激活阶段时长。 |
revision | int | 0 | 缓存身份计数,不限制范围。 |
specialTravelActive | boolean | false | 特殊移动激活标志,与处理器当前是否处理移动不同。 |
jumpInput | boolean | false | 特殊移动接受的跳跃输入。 |
sneakInput | boolean | false | 移动或姿态接受的潜行输入。 |
移动轴、主攻击间隔与连段、缓存实体、旋转快照、到期消息抑制和客户端尺寸记录都不序列化。组件读取不会重新验证阶段与 ID 的所有组合,因此损坏的激活存档可能无法构建形态。直接编辑 NBT 不是受支持的进入路径。
捕获实体 NBT 时移除 UUID Pos Motion Rotation Dimension PortalCooldown FallDistance Fire Air OnGround Invulnerable Health HurtTime HurtByTimestamp DeathTime AbsorptionAmount Passengers Leash Brain CanPickUpLoot PersistenceRequired Owner OwnerUUID Tamed Sitting,再写入请求的 id。这是黑名单,并非视觉字段白名单;其他实体专属字段仍保留。工厂在 readNbt 前清理,然后禁用生物 AI。
人形变形请求还携带 MorphHumanoidAppearance 复合标签,保存解析后的 HumanoidProfile,包括当前服装。复制实体时取其已呈现的外观;仅指定 NPC 类型的请求先在服务端解析预设,再生成快照。工厂读取普通实体 NBT 后恢复该外观,因此客户端无需加载服务端专属的 NPC 预设。快照属于本次变形,保存在 entityNbt 内,不改变 NPC 存档格式。
能力请求
morph_ability_use 携带槽位字节、动作字节和目标实体 VarInt。槽位为 PRIMARY、SECONDARY,动作为 PRESS、REPEAT、RELEASE。非法枚举序号抛出异常。服务端要求 ACTIVE、形态 ID、可构建形态,且不属于保留玩家控制的形态。
执行前先解析实体覆盖。冷却使用显示解析后的能力 ID,键为 <namespace>:morph_ability/<path>。冷却期间拒绝重复输入;新的按下仅在能力允许 acceptsPressDuringCooldown 时执行。释放绕过激活冷却检查。接受结果会广播预览,只有正的返回冷却才更新冷却管理器。
数据包目标只是解析成生物实体,各能力仍须自行检查距离、视线和友方关系;数据包不保证目标有效。来源元数据从玩家当前激活且执行 ID 匹配存储来源的触发能力获取;没有来源能力时采用处理器默认值。
主攻击间隔与能力冷却分开,最少 1 tick。延迟攻击使用 MorphAttackScheduler,它会丢弃已移除玩家或属于另一服务端的玩家。回调仍须在施加延迟命中前检查阶段、修订号和目标有效性。
控制、姿态与装备
MorphControlPolicy 将 BaseNpcEntity 及 isekaiexpansion:morph_player_rigs 类型视为玩家骨架。激活的玩家骨架保留玩家操作,模块化形态使用变身能力输入。变身各阶段中,模块化形态的手部访问仅暴露兼容 Better Combat 武器,且形态必须被 Better Mob Combat 允许。其他手持栈解析为空,但不会从库存移除。玩家骨架保留普通手部访问。
非玩家骨架在变身尺寸接管身体时阻止原版蹲伏和爬行。干燥且未滑翔的 SWIMMING 姿态也视为解剖结构上的蹲伏,真正游泳和滑翔仍分别处理。可驯服形态在激活、特殊移动关闭、潜行输入按住且水平速度平方不超过 0.0025 时坐下。
激活形态可继承水下呼吸和火焰免疫。isekaiexpansion:morph_climbers 在水平碰撞时允许攀爬,isekaiexpansion:morph_fall_damage_immune 抑制坠落伤害。这些特性要求 ACTIVE,不只是过渡中的形态可见半段。
移动与乘客权限
只有服务端和所有者客户端驱动移动,观察者客户端返回放行结果。morph_input_state 将前后、左右轴按 127 缩放为有符号字节,并发送跳跃、潜行布尔值。轴值限制为 −1…1。激活的可驯服非玩家骨架接受潜行姿态输入,已注册移动的形态也接受移动和跳跃;不支持的输入清空。
移动激活拒绝旁观者、骑乘者、未激活形态或不支持的处理器。客户端预测还要求处理器显式支持。服务端读取保存输入,所有者客户端读取本地输入。处理器可以在未设置激活标志时接管非激活移动。失败会记录日志并清除或停用标志;尽管日志措辞像是永久禁用,注册项并未移除,后续移动仍可能再次调用。
乘客骑乘的是真实玩家宿主。登乘要求以空主手交互另一玩家,且对方为激活形态并注册了乘坐处理器;具体资格由处理器决定。座位和下车位置交给处理器计算。受支持的激活载运关系中,宿主与乘客双向伤害会被抑制;此检查不会让同一宿主上的所有乘客彼此免伤。
被载运旋转将形态身体 yaw 增量和处理器 pitch 增量加到乘客,pitch 限制为 −90…90。退出时弹出受支持乘客。宿主还会收到显式乘客列表数据包,确保载具玩家自身也看到骑乘关系。
变体选择与护符
变体选择独立于当前变身。NBT Selections 是由 Form、Variant 标识符字符串构成的 compound 列表;非法 ID 跳过,重复形态以后面的值为准。修订号只在本地使用,读取或更改选择时递增,不保存。此 NBT 列表没有选择数量上限。
选择请求要求存在支持的提供者、玩家持有该精确形态的变身能力,以及提供者列出了请求变体。仅有临时变身护符不满足能力所有权检查。发布目录时,只对仍受支持的提供者清理不再提供的选择;失去所有权或提供者不存在,本身不会删除已保存选择。
服务端变体目录在加入和成功数据重载时发送。网络读取器最多接受 256 个形态、每形态 64 个变体、每翻译键 256 字符;非法数量抛出异常。原生提供者在代码中定义变体,没有通用变体 JSON 加载器。
护符堆叠上限为 8,需要持续使用 40 tick。服务端成功开始变身后,非创造模式消耗一个,失败不消耗。内置稳定阶段时长为猪灵 120 秒、猪灵蛮兵 45 秒、铁甲僵尸 90 秒,过渡均为 20 tick。僵尸请求提供铁甲 NBT。请求默认两项能力为 none,但实体覆盖仍可能提供动作。
扩展方式
对不应替换已有形态的授予,使用 MorphFormRequest.start;调用底层服务前则应主动处理现有状态。明确清理、权限和空间检查。物种行为使用已注册 tick、移动或乘坐处理器,不把合成形态当普通生物生成或 tick。
阶段监听器在同步后看到完整状态,也可能在客户端接收 NBT 时执行,游戏逻辑应检查侧别。延迟回调需捕获并复核修订号;仅凭宿主 UUID 不能认定仍是同一次形态会话。
不要把 NBT 清理器当作通用不可信实体模式验证器。它仅移除所列临时键,其余任意 compound 都保留。新增宿主或形态状态时,应纳入对应持久化、同步和缓存失效约定。
验证
isekaiexpansion:test_item 是开发测试道具。持续使用 40 ticks(2 秒)进入 Evelina 形态;完成使用时潜行则进入全套铁甲僵尸形态。两种请求都不限时,过渡为 18,编写的能力均为 none。僵尸变身成功后,真实主手会换成铁剑;被替换的主手物品和测试道具副本尝试放回库存,放不下则掉落。这项操作会改变库存,应使用测试角色。
权限等级 2 可使用 /ise dev morph <entityType> 创建无限形态:过渡 18、来源 isekaiexpansion:dev_morph、配置能力 none,但实体覆盖仍生效。/ise dev morph 请求正常返回。未知或非生物实体、骑乘和空间不足会拒绝进入。
使用专用服务端及观察客户端,检查进入和退出中点、奇数过渡长度、矮小和高大形态、受阻返回、重连、重生及跨维度。撤销来源能力,并与程序化授予对比。
将主攻击间隔与副能力冷却分开验证。冷却中分别发送按下、重复、释放,检查遮挡、过远、友方目标,以及换形后的延迟攻击。确认被过滤物品仍在库存。
移动需比较所有者与观察者、处理器激活和非激活路径、输入释放、登乘、下车及携带乘客退出。验证宿主与乘客伤害保护,但不要假定同载乘客互相免伤。确认限时形态到期受阻后,在出现站立空间时能返回。