四元素 UNITTHEME 显示与挂点保存:v46

2026-09-20。本批接入冰冻、燃烧、中毒、感电的原版主题粒子,并把会消耗游戏随机数的骨骼选点从显示层移入 CoreSim。感电主题能显示不代表 Charged Bolt 已完成;元素武器准入仍未开放。

原版定义与控制流

原数据与 IDA 导出:661630(粒子字段)、53F1D0(类型筛选 / 数量)、51C030(骨骼选择 / 挂载)、5150E0(父词缀之后的主题增删)。

主题原 LAYOUT数量挂点
FROZENMEDIA/PARTICLES/MONSTERS/FROZENSMALL.LAYOUT8Random
BURNINGMEDIA/PARTICLES/MONSTERS/ONFIRESMALL.LAYOUT10Random
POISONEDMEDIA/PARTICLES/MONSTERS/POISONSMALL.LAYOUT10Random
ELECTRICITYMEDIA/PARTICLES/MONSTERS/ELECTRICSMALL.LAYOUT10Random

四者要求 CHARACTER,排除 MONSTER TURRET。BLEEDING 的旧 CHARACTER / NOBLEED 筛选保留。

661630 的默认值不可按“字段省略就是 false”解释:

  • ATTACHES 默认 true;
  • FOLLOWS 默认 !ATTACHES;
  • COUNT 默认 1;显式 0 在消费者中仍生成 1 份。

因此省略两个布尔值的 Frozen / Poisoned 也是附着骨骼,不是另造一个脚下光圈。选中的五个主题没有 REMOVAL_UNITTHEME / RIMLIGHT,未用假实现扩展这些分支。

Random 的 RNG 不是显示层自己的随机数

51C030 对 Random 使用原 volatile 整数随机流:

  1. 在原骨骼索引空间选择 [0, boneCount - 1]。
  2. 骨骼名转大写,前三字符不是 TAG 则接受。
  3. 最多尝试 30 次;30 次全是 TAG 时保留最后一次结果,不改成 root。
  4. 单骨骼区间不推进 RNG;没有骨骼或固定名字不存在时走 root,不编造随机骨骼。

不能预先删掉 TAG 后在剩余集合抽签:分布及 RNG 消耗都变了。也不能在 Godot 每次重建节点时重新抽签,否则后续战斗会受画面重建次数影响。

NativeThemeBindings 在父词缀清理之后、CStat 更新之前处理主题;先添加新主题,再移除旧主题。多个效果引用同主题,只生成一组实例。刷新不重抽,删除按原 swap-last 方式处理。

原索引与 Godot 骨骼索引

Godot Skeleton3D 的层级顺序不是原 Ogre handle 顺序。

导出器读取 pose_to_gltf.py 生成的 glTF / GLB skin.joints。该导出器按原 rig handle 排序;运行时将选出的名字映射到真实 Godot Skeleton3D 的 bone index,而不直接把随机整数当作 Godot index。

当前 schema 2 清单包含:

  • 五个主题的原 DAT / LAYOUT SHA256、类型规则、数量、挂载布尔值;
  • 1811 个现有 pose 导出模型的有序骨骼表;
  • 既有 UNITTHEMEOFFSET 子覆盖父定义。

玩家需要绑定 char_root,不能绑定仅含碰撞胶囊的 PlayerBody:两者是兄弟节点。否则会误判无骨骼、把主题放到脚底并漏掉随机选点。本批修正了正式模型绑定和显示入口,并新增玩家八骨骼挂点及 GPU 检查。

实际 ECHO PASS 受测模型为 sturm_ranged__idle_run_polearm1_die1__right_spear_c_ranged_sturm_xtra.glb。已核对 GLB 中的原 skin.joints 与清单相同,选中的每个名字均在实际 Skeleton3D 中找到。

未知 rig 不猜成随机骨骼。不同资源但骨骼表相同可复用选点;活动主题下骨骼拓扑变化仍明确拒绝,等待专门的重新挂载行为核对。

v46 与显示生命周期

UnitSnapshot 新增 ThemeBindings,记录目录指纹、模型、主题实例 ID、原粒子行 / 序号 / 选中骨骼名。

  • 捕获 / 恢复复制数组,读档保留选点;
  • 加载后重新绑定冻结的主题数据与观测到的模型;
  • 同一主题 / 实例 / 选点不重复实例化;
  • 同时刻加载不同分支时比较选点签名,不仅依赖 clock 变小;
  • 显示层只跟随已选骨骼的实际世界姿态,无战斗随机数调用;
  • 移除后停止发射,按现有持续粒子排空流程释放;
  • 读档回退、对象替换或销毁清理显示节点;
  • 普通尸体保留仍存活的主题,最后来源到期才移除,不凭死亡状态清空所有效果。

缺少后续单位模型时,之前单位已经选出的骨骼和随机数也随整帧回滚。纯主题变化没有 HP / DoT 工作时仍会进入主题处理阶段。

v46 是移植端完整模拟 / 重放快照,不是宣称与原版 SAV 的视觉存储格式相同。

实际 GPU 验证

build/elemental_theme_visual/result.json 记录源文件 / 截图哈希、Vulkan、退出码、错误列表和默认存档哈希。

实际 ECHO PASS 中验证:

  • 四种原主题各自显示 8 / 10 / 10 / 10 份;
  • 所有选点映射到真实骨骼,实例位置与骨骼姿态误差 < .001;
  • 反复显示同步不改模拟状态或 RNG;
  • 活动期间不重启粒子;
  • 保存 / 恢复和显示层重建复用同一组名字;
  • 移动仍正确附着;
  • 玩家使用 hum_f 原视觉 rig,八个 Frozen 挂点均映射到真实骨骼,不回退到物理胶囊;
  • 删除来源后停止发射并排空,活动 / draining / 子节点均为空。

主题源在该 GPU 探针中明确注入,以单独检查显示消费者;没有把它当作自然武器 HIT 或 Charged Bolt 验收。三元素正式分派的实际桥接探针另行通过。旧 BLEEDING 原武器 Drop → Pickup → Equip → authored HIT、NOBLEED、尸体、重放与释放 GPU 回归也通过。

Vision review — 局部 FX 工程检查

已查看四元素、移动燃烧、全部清除的实际 WebP;短边 512。UI 仅在探针中隐藏,未改正式布局。没有观察到大黑底矩形或清理后残留的主题节点。

指标分数 / 2观察
COMP-FOCAL-SINGLE2受测怪物为主要观察对象
COMP-SIL-ACTION2四肢 / 武器轮廓保留
COMP-DEPTH-LAYERS2前景怪物、玩家及场景层次可辨
LIGHT-KEY-FILL1夜雨下暗部偏重
LIGHT-PART-READ1冰冻 / 中毒受雨幕干扰
LIGHT-BLOOM-ABUSE2发光未抹掉模型边缘
LIGHT-PART-OVER2未形成遮挡大面积画面的软面片
MOT-TRAIL-SOUP2移动检查未见持续拖尾堆积

14 / 16,87.5%,局部 B;零分项无,适用硬门未触发。UI / 字体 / 图标不在这个工程裁剪的检查范围内。后续优先与原版同地图、同时间、同天气对拍 LIGHT-PART-READ / LIGHT-KEY-FILL,不凭本图自行提高亮度。此评分不是全游戏视觉认证。

回归与剩余内容

  • 2003 条核心断言通过。
  • 430 项相关 Python 回归通过。
  • Godot C# 构建零警告 / 零错误,核心静态检查无硬错。
  • 独立数值 / codec Godot 34 项继续通过。
  • 新四元素 GPU、三元素正式桥接、旧 BLEEDING GPU 检查通过。
  • 导入仍有既有 honoredpath_pb / echopass_pb 重复 UID 警告,本批未改两张场景。

仍需完成:元素命中反应、角色来源仇恨 / AI、TYPE81 Charged Bolt 安装 / 触发 / 移除、更广观察者、其他武器效果,以及逐武器实际 HIT / 视觉对照。未覆盖的主题删除附加主题 / rimlight / 不同骨骼拓扑切换也不作已完成声明。

武器构造检查仍为 1099 / 1419,273 阻塞、47 基础缺口、0 构造异常。全武器目标未完成。

遵循 godot-master:会影响模拟的随机选点由 CoreSim 持有;Godot 只表现,并以实际 GPU 图检查回收和显示。main 原地、未提交、未 attach 原游戏。默认存档 SHA256 未变: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f