原版属性派发、依赖回调与默认快照
本批结果
已新增NativePropertyDispatch并把10图空间属性投影改为经过该派发器,不再只是逐项赋值后一次性计算姿态。
- 2048组原生派发场景的对象值、调用顺序、参数长度、递归保护位与存储结果一致。
- 72组原生字节缓冲规范化场景一致。
- 原默认快照捕获/再次捕获/回放实验,确认副本不携带对象回调。
- 1212条核心断言、138项相关Python检查通过;Godot C#构建零warning/error,coresimlint通过。
- 原10图22354条Room Piece空间输入继续通过。
仍未迁移所有非空间setter、完整对象工厂/父节点关联/资源装载/初始化。武器构造覆盖仍1053/1419,289个场景变体仍需真实加载RNG和调用顺序。
默认记录:旧假设需要纠正
4CBBF0并不是给每个对象再执行一套固定默认setter:
- 仅在descriptor+0xF8的快照数量为0时,按注册顺序捕获。
- 4DAAF0 → 4DA150从首个已创建对象的getter读取值,形成属性副本。
- 有prototype参数时,副本复制编号/类型/标志和数据,不复制getter、setter、枚举转换器或依赖列表。
- 0x20000标志的副本另列入descriptor+0x104集合。
- 50B220在显式属性前遍历这个集合,但回放仍遵守4DA040的“无setter则只存缓冲”分支。
原生实验以3条属性、2条带0x20000的记录验证:三份快照的三个回调指针全部为0;再次捕获不会重读已改变的prototype;回放到另一对象时对象值不变,没有setter事件。
因此不能把这个循环理解成“再把XYZ等字段重置到默认值”。原Room Piece的XYZ确实带0x20000,但其快照回放和对象setter是两条不同路径。
本批实现Capture/Replay以及显式previous快照复用。它们是加载操作输入/结果,目前没有持久descriptor注册表拥有整个缓存生命周期。
普通派发:setter在保护位之前
4DA040:
payload为null → 无动作
有目标 && 原setter指针存在:
4D8D80尝试调用setter
若全局依赖保护位为0:
保护位=1
逐个读取当前依赖属性的值,并派发给依赖
保护位=0
否则:
更新属性自身的存储缓冲4D8D80还有独立条件:原getter指针必须存在,才调用setter。 所以“setter存在但getter不存在”时,直接写入被跳过,但外层仍可能展开依赖。
保护位在setter返回后才设置。setter内部触发的嵌套派发仍可能展开自己的依赖;若把保护提到setter之前,会吞掉合法更新。
保护是原全局byte317E768,不是每个对象或每个属性独立一份。真正的加载宿主必须共享一个NativePropertyDispatch上下文。
依赖是实时读取,不是预先拍快照
原循环每次读取live依赖数量,并在轮到该依赖时调用getter:
- 先前setter修改的值会被后续getter看到。
- setter中新增的依赖可能在同轮执行。
- 保护位只禁止继续展开依赖,不禁止被调setter自身。
- 缺getter时可读取该依赖的已有存储数据;无有效数据则跳过。
测试覆盖setter内重入、后续getter读到91的新值、循环中追加第4个依赖,以及缺getter/缺setter的分支,不只对最终值做比较。
字节数、word count与字符串指针
原getter返回字节数;4D8FC0把它转换为4字节word count:
- 普通数值且字节数是4的倍数:直接引用原缓冲,count=bytes/4。
- 字符串/枚举缓冲,或非4字节对齐:count=floor(bytes/4)+1,零填充后拷贝。
- 字符串即使已4字节对齐,也保留额外终止空间。
- 小于4字节的枚举getter值按有符号byte解释;0xFE成为-2,不是254。
4DA2A0还有一个必须保留的细节:它传给4DA040的是有效、已终止的字符串指针,但word count参数是字面0。 原string setter仍能读字符串;枚举转换分支会先转成int,再以4字节调用setter。
NativePropertyPayload因此分开保存Bytes和WordCount,不能用数组长度替代原传参。 测试区分了普通字符串“17”的count=0与枚举转换后17的count=1。
已接入的空间属性
NativeSpatialProperties为POSITION、FORWARD、RIGHT、UP、XYZ提供绑定,并保留4B4430注册的依赖关系:
FORWARD → RIGHT、UP
RIGHT → UP更新方向列时立即调用已验证的四元数转换/归一化内核,依赖setter按原顺序再次执行。 F2BinaryRoomInputs.ProjectLocalPose已改为使用这套绑定与派发,但名称仍是空间“投影”:已知非空间字段仍不在这条投影接口执行。
接口区分“原函数指针不存在”和“原指针存在但移植回调尚未实现”。后者报明确缺输入,不能伪装成原版的null回调来跳过工作。
原生验证及边界
独立32位进程执行原:
- 4DA040、4D8D80、4D94E0、4D8FC0。
- 4DA2F0/4DA2A0的字符串分支。
- 4CBBF0、4DAAF0、4DA150的快照捕获。
- 4D9690及原存储路径的回放。
原始EXE SHA256: 186472c3057b38f4cdff4696959a943c396ae6166995f7418997b5ea853e8a5e。
明确适配边界:
- getter/setter为可观察的测试回调,不代表所有游戏属性的具体行为。
- 枚举解析/格式化为测试适配器;真正游戏枚举仍需绑定各自原语义。
- 标准字符串元数据和内存操作使用受限适配。
- 测试分配器将已退休块保留到单个案例结束,隔离缓冲自别名与堆复用影响;没有宣称原分配器释放后内容逐位等价。
- 仅重定位了4处构造函数指针常量,未修改原文件,重定位清单受测试检查。
- 托管异常路径使用finally恢复保护位,防止诊断失败污染后续探针;原异常/堆故障行为未移植。宿主仍需处理失败操作的状态隔离。
正常路径中,控制顺序和所测数据结果均与上述原指令一致。完整属性数值文本tokenizer、全部枚举、实际资源副作用及descriptor缓存持久化仍未完成。
产物与下一步
后续:Room Piece资源设置时序已核对GUID/VISUAL的延迟刷新和override行为;真正资源加载宿主及对象工厂仍未完成。
- core_sim/NativePropertyDispatch.cs。
- core_sim/NativeSpatialProperties.cs。
- core_sim.io/F2BinaryRoomInputs.cs。
- build/native_property_dispatch_oracle/results.json。
- build/native_property_dispatch_core.log:1212断言。
- build/native_property_dispatch_python.log:138检查。
本批按godot-master的数据/表现分层,新增的是加载执行基础与空间接线,不改现有地图画面。main原地工作、未提交、未attach原游戏。 默认存档hash保持: 9840fe858b6e311c73f8c2d4ed49912d59d71365f6278392811730e012d32a7f。
下一批继续实际Room Piece的GUID/资源setter、对象工厂、父节点关联和初始化,再连接全局RNG边界、世界分区与攻击型触发技能。全武器目标未完成。