原版 BINLAYOUT 执行装载控制
本批结果
新增 core_sim/NativeLayoutLoader.cs,将前批完整二进制文档推进到统一执行装载控制:
- Group 预选上下文与同步 RNG 保存/恢复。
- 描述符解析、创建前筛选、工厂创建、属性应用。
- 创建后 Group 接受检查与拒绝销毁。
- 接受列表、首条优先的 SourceId 映射、扩展程序队列。
- 扩展处理、统一初始化、描述符后处理和场景收尾。
5,120 组参考直接执行原版正常二进制路径的 50BA10、递归 50B680、4D8710 和 RNG 保存/恢复;移植结果的对象列表、字段、映射、随机状态和调用顺序全部一致。
累计 1279 条核心断言、167 项相关 Python 检查通过;Godot C# 构建零警告、零错误,coresimlint 通过。
这是执行装载控制器,不是所有宿主回调的完整实现。 Group 选择算法、各类实际对象/属性/extra 解释器、视觉后端和世界注册仍由明确宿主接口承担,尚未全部接入正式地图。全武器目标未完成,构造覆盖不因本批测试改算。
与完整数据入口连接
F2NativeLayouts 的文档、记录和属性实现核心只读接口,无需再把数据重组为仅包含 Room Piece 的列表。
新增保留:
- SourceBytes:完整原始文件输入缓冲。
- ExtraOffset:原 extra 在文件中的精确起点。
因此扩展解释器既能获得当前 payload,也能在有证据支持时使用完整源文件上下文;没有强行将原版接收的完整 reader 缩成一个无法跨引用的短 buffer。
已重新运行全量独立 C# 核验:8,987 文件回写/属性指纹继续一致,44,696 条实际 Group 对象块引用匹配,2,528 条合成根,无未解析引用。
50B680 的对象执行顺序
- 空记录直接返回。
- 解析 descriptor;确实不存在时跳过整棵子树。
- 当前 descriptor 为 Group,且实际 Group pool 非空时,先询问 pool 是否允许该 SourceId。
- 有继承上下文且其 byte+98 开启限制时,只允许 Layout Link 或 Layout Link Controller;否则跳过整棵子树。
- 调用 NativeSceneFactory.Create,不传模板、不传立即父对象、不立即初始化。
- 符合条件时先应用继承的 feature 上下文。
- 经对象虚入口设置父 RuntimeId。
- 直接写原 SourceId。
- 执行属性处理。
- 对 pooled Group 执行 61F660 接受检查;拒绝则销毁对象并跳过其子树。
- 接受的 pooled Group 先清 byte+607,再读取 pool 标志,写 byte+602。
- 将对象加入接受列表。
- 建立 SourceId → RuntimeId 映射。
- 非空 extra 入队,暂不执行。
- 为 pooled Group 查找新的子上下文;查不到则继承原上下文。
- 递归读取子记录,每次使用父对象当前的 RuntimeId。
接受列表的顺序是实际成功执行并接受的预序,不是全部源记录,也不能通过事后剔除对象来假装等价。被创建后拒绝的对象已经产生过构造/属性副作用,必须由实际销毁后端处理。
普通 Group 在没有 pool 时不走 pooled Group 的接受/标记分支。
两个上下文字段不能误认
- 50A3E0 只做两个 descriptor 身份比较:Layout Link 与 Layout Link Controller,不是宽泛的“所有 feature 对象”分类。
- 继承上下文的 byte+98 控制是否限制为这两类;它不是尾部序列化的 NO TAG FOUND byte+25。
- 上下文 +92 为本次解析后的 tag。
- loader+112 允许、类型匹配,而且“byte+98 开启或 tag!=-1”时,才在属性之前调用 50ABE0。
核心接口按这些行为命名,不将 byte+98 和原始尾部布尔字段合并。
SourceId 映射:4D8710
- SourceId=-1 或 RuntimeId=-1 时不建映射。
- 键首次出现:保存当前 RuntimeId。
- 键重复:记录问题,但保留首条值。
- 重复 SourceId 的对象本身仍可各自存在于接受列表。
因此不能用字典覆盖来选择“最后一个对象”,也不能因键重复直接去掉后续场景对象。核心映射保留完整 signed Int64,另有边界测试覆盖最小/最大值。
原版实际映射函数参与本批机器码参考,不只由测试桩重复实现预期结果。
顶层装载阶段
NativeLayoutLoader.Load 对 v11 正常二进制输入执行:
- 确认 Group、Layout Link、Layout Link Controller 三个必需描述符;确实缺少时返回明确 MissingDescriptors 状态。
- 将文件第二字节 flags 传给场景布局版本相关状态。
- 若文件有 Group 尾部,读取 pool。
- 在 pool 读取之后保存完整同步 RNG 状态。
- 执行 pool 预选。
- 恢复 RNG,再进行预选后的处理。
- 读取根对象。
- 按 extra 队列执行扩展程序。
- 按接受列表调用对象当前 descriptor 的初始化入口。
- 场景 +312 接收源映射。
- 描述符后处理 4D88C0。
- 查询场景 +52,再将结果交给 +48。
- 4D6630(force=true) 刷新场景 Group。
- 场景 +316 收尾。
+52/+48 保留为实际场景回调边界,没有凭槽号将其误写成通用 visible 设置。
根记录数量的原检查是 signed short;子记录数量是 unsigned short。核心保留该差异,另测根数量高位设置的路径。当前原版文档仍由严格读取器先验证边界。
原私有 context 的内存分配/释放、进度 UI、文本回退路径和错误 reader 的容错字节计数不属于本核心正常路径的完整等价性声明。
RNG 边界
原顺序为:
读取 Group pool
保存 g_seed_synced 的 lo/carry
预选 Group
恢复完整状态
预选后处理
创建实际对象676970 恢复全零的 64 位状态时,会改用 GetTickCount,carry 为 0。非零状态不触发时钟读取。核心通过宿主明确提供该外部输入,不在纯核心中调用系统时钟。
恢复只还原随机状态;Mwc.TotalAdvances 是移植端的诊断计数,不因状态恢复而倒退。
真实宿主仍须让后续对象构造/ID 生成、视觉选择及其他消费者使用正确的同一同步流。此处的保存恢复不意味着整张地图随机调用序列已经全部补齐。
队列是动态的
50BA10 在循环中重新读取当前队列长度:
- extra 处理期间新增的 extra,仍会在本轮处理。
- extra 期间加入的接受对象,进入后续初始化。
- 初始化期间加入的接受对象,也在本轮初始化。
- 若调用方要求输出对象列表,先把当前对象加入输出,再执行其初始化。
核心没有在进入阶段前 ToArray 成固定快照,也没有把初始化新增对象统一推迟到下一帧。
测试夹具明确追加了 runtime 2000/source 999 的 extra 对象和 runtime 3000/source 998 的初始化对象;原版与移植遍历顺序一致。它们是控制测试输入,不是原版武器/地图对象定义。
文件头名称不执行 setter
50B680 在 v11 读取对象名称到临时 wstring,随后销毁该临时字符串;这条路径没有把它送入名称 setter。
文档仍完整保留 wire name,但执行器不因读取名称而主动改对象运行时名称,也不将其当脚本或指令执行。
真实 Room 叶节点组合验证
从原版 PASS_JD_A 选择一个无子记录、无 extra、全部属性均已有实现的真实 Room 叶节点:
- SourceId:4658743717804970463。
- 通过统一 Load 控制器,而不是直接跳到资源初始化。
- 工厂创建对象,按原字段应用位置/方向/缩放、GUID 和 VISUAL。
- 属性阶段不提前请求视觉模型。
- 在统一初始化阶段进入 NativeRoomResourceLifecycle 和真实 F2NativeRoomResourceHost。
视觉模型后端仍是明示夹具。此测试不外推为全部 Room 属性、所有地图对象或正式场景已完成;不支持的字段没有通过丢弃来让样例通过。
参考工具与边界
原 EXE SHA256: 186472c3057b38f4cdff4696959a943c396ae6166995f7418997b5ea853e8a5e。
- tools/build_native_layout_loader_oracle.py/tools/native_layout_loader_oracle.c。
- 原样执行正常二进制装载函数、递归记录函数、源 ID 映射、同步 RNG 保存/恢复。
- 文件读取、分配器、字符串、descriptor、工厂、属性、Group 规则、extra 和实际场景操作使用明确 spy。
- 保留完整调用状态;参考工具额外检查确实覆盖创建、拒绝和映射,不能只靠大量空返回冒充覆盖。
- 描述符 wire code 的实际参数是 byte,原调用的 DWORD 高位可有无关栈内容;参考桩按真实宽度读取。
- 原装载函数清理后,不能再读取其局部栈向量;工具在场景收尾时复制取样结果。
- 所有探针在隔离 32 位进程运行,没有 attach 原游戏。
产物:
- build/native_layout_loader_oracle/results.json:5120 案例及完整状态/调用顺序。
- build/native_layout_loader_core.log:1279 断言。
- build/native_layout_loader_python.log:167 检查。
- build/native_layout_loader_godot.log:零警告、零错误。
- build/native_layout_csharp_audit.json:更新后的全量数据入口核验。
尚未完成的宿主工作
INativeLayoutLoadHost 没有默认“成功空操作”实现。实际宿主必须落实:
- 真正的 Group pool 解析、选择、模式/主题/唯一性上下文。
- 每种 descriptor 的构造和销毁。
- 全属性默认值/setter 绑定。
- 逻辑/时间线等 extra 的真实解释和引用修复。
- 实际节点/模型/碰撞注册和世界分区。
Finished 仅表示这套装载控制与提供的宿主回调正常走完,不是完整世界查询资格或全武器完成标记。正式接入前应使用可丢弃的分阶段场景宿主;失败不会在本核心里假造成功、自动改存档或隐式回滚未知外部副作用。
NativeLayoutLoadState 当前是单次装载临时状态;尚未纳入持久世界和快照,v29 未改。按 godot-master 的分层方式,本批没有替换正式地图画面。
main 原地工作、未提交;默认存档 SHA256 保持: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f。
下一批继续 Group 选择和具体场景宿主,将这条执行路径接到真实世界注册,再补完整攻击型触发技能与全武器验收。