原版属性派发、依赖回调与默认快照

本批结果

已新增NativePropertyDispatch并把10图空间属性投影改为经过该派发器,不再只是逐项赋值后一次性计算姿态。

  • 2048组原生派发场景的对象值、调用顺序、参数长度、递归保护位与存储结果一致。
  • 72组原生字节缓冲规范化场景一致。
  • 原默认快照捕获/再次捕获/回放实验,确认副本不携带对象回调。
  • 1212条核心断言、138项相关Python检查通过;Godot C#构建零warning/error,coresimlint通过。
  • 原10图22354条Room Piece空间输入继续通过。

仍未迁移所有非空间setter、完整对象工厂/父节点关联/资源装载/初始化。武器构造覆盖仍1053/1419,289个场景变体仍需真实加载RNG和调用顺序。

默认记录:旧假设需要纠正

4CBBF0并不是给每个对象再执行一套固定默认setter:

  1. 仅在descriptor+0xF8的快照数量为0时,按注册顺序捕获。
  2. 4DAAF0 → 4DA150从首个已创建对象的getter读取值,形成属性副本。
  3. 有prototype参数时,副本复制编号/类型/标志和数据,不复制getter、setter、枚举转换器或依赖列表
  4. 0x20000标志的副本另列入descriptor+0x104集合。
  5. 50B220在显式属性前遍历这个集合,但回放仍遵守4DA040的“无setter则只存缓冲”分支。

原生实验以3条属性、2条带0x20000的记录验证:三份快照的三个回调指针全部为0;再次捕获不会重读已改变的prototype;回放到另一对象时对象值不变,没有setter事件。

因此不能把这个循环理解成“再把XYZ等字段重置到默认值”。原Room Piece的XYZ确实带0x20000,但其快照回放和对象setter是两条不同路径。

本批实现Capture/Replay以及显式previous快照复用。它们是加载操作输入/结果,目前没有持久descriptor注册表拥有整个缓存生命周期。

普通派发:setter在保护位之前

4DA040:

text
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注册的依赖关系:

text
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边界、世界分区与攻击型触发技能。全武器目标未完成。