外观
Building Record 建筑记录
状态:Authoritative Reference v1
1. 物理结构
BTL Building record 固定为:
text
0x20 = 32 bytes当前 1.28.0 corpus:
text
Building records = 32127原版构造链将每条 Building 记录定位到 Tile,并由 FUN_004759D8 等路径构造/应用建筑状态。Building record 中多个字节是 packed/mixed state,因此“能读出某个低位值”不等于整字节可独立编辑。
主要证据:
text
reports/btl_v1280_so_recovery.md
reports/btl_editor/round4/field_write_whitelist_matrix.csv
reconstruction/src/WC4.Runtime.BattleData/BtlRecords.cs
reconstruction/docs/rendering/static_city_summary_integration_report.md2. 完整 byte map
| Offset | Size | Raw type | 当前中文语义 / code name | 状态 | 写入边界 |
|---|---|---|---|---|---|
+0x00 | 2 | uint16 LE | Building Tile ID / TileId | Confirmed | 需独立占用/引用验证 |
+0x02 | 2 | int16 LE | 建筑名称/显示身份 ID / NameId | Confirmed | NotAssessed |
+0x04 | 1 | uint8 | Building type / BuildingType | Confirmed | NotAssessed |
+0x05 | 1 | uint8 | appearance raw / Appearance | Confirmed | NotAssessed |
+0x06 | 1 | uint8 | CityFeature ID / CityFeatureId | Confirmed | NotAssessed |
+0x07 | 1 | uint8 | decoration type / DecorationType | Confirmed | NotAssessed |
+0x08 | 2 | uint16 LE | type-dependent unlock/resource/feature ID / UnlockOrFeatureId | Partial | NoGo |
+0x0A | 2 | uint16 LE | type-dependent reward/parameter / RewardOrParameter | Partial | NoGo |
+0x0C | 1 | int8 | signed priority / PriorityRaw | Confirmed | NotAssessed |
+0x0D | 1 | uint8 | objective marker / ObjectiveMarker | Confirmed | NotAssessed |
+0x0E | 1 | int8 | capture Event ID / CaptureEventId | Confirmed runtime projection | 需 Event 引用诊断 |
+0x0F | 1 | raw byte | 未闭合 raw;当前 corpus 全零 | Unknown | NoGo |
+0x10 | 2 | int16 LE | initial health/stage raw / InitialHealthStageRaw | Partial | NoGo |
+0x12 | 1 | raw byte | active raw / Header12Raw | Partial | NoGo |
+0x13 | 1 | raw byte | active raw / Header13Raw | Partial | NoGo |
+0x14 | 1 | packed uint8 | mixed building state / PackedState14 | Partial | NoGo whole-byte edit |
+0x15 | 1 | packed/raw uint8 | mixed/未闭合 state / PackedState15 | Partial | NoGo |
+0x16 | 1 | uint8 | air-defence type / AirDefenceType | Confirmed | NotAssessed |
+0x17 | 1 | packed uint8 | air-defence/other flags / PackedAirDefenceFlags | Partial | NoGo whole-byte edit |
+0x18 | 1 | uint8 | Factory facility level / FactoryLevel | Confirmed | type validation required |
+0x19 | 1 | uint8 | Research facility level / ResearchLevel | Confirmed | type validation required |
+0x1A | 1 | uint8 | Medical facility level / MedicalLevel | Confirmed | type validation required |
+0x1B | 1 | uint8 | Airfield facility level / AirfieldLevel | Confirmed | type validation required |
+0x1C | 1 | uint8 | Missile facility level / MissileLevel | Confirmed | type validation required |
+0x1D | 1 | packed uint8 | low 3 bits Nuclear level + active extension bits / PackedNuclearAndExtensionLevel | Partial | NoGo whole-byte edit |
+0x1E..+0x1F | 2 | raw bytes | 未闭合 tail bytes | Unknown | NoGo |
+0x10 是一个完整 int16;+0x11 只是这个 word 的第二个物理字节,不是另一个可独立编辑字段。旧审计中若按 byte 列出 +0x11,只能视为重叠观察面。
2.1 +0x0E CaptureEventId 的磁盘 / runtime 投影
Android 1.28.0 原版 FUN_004759D8 直接执行:
text
00475BA8 ldrsb w8, [BuildingRecord+0x0E]
00475BAC str w8, [runtime Tile+0x150]因此磁盘 int8 CaptureEventId 会符号扩展后进入 runtime Tile 的 int32 capture-Event 槽。反向序列化 FUN_004757E0 又直接执行:
text
00475984 ldr w8, [runtime Tile+0x150]
00475988 strb w8, [BuildingRecord+0x0E]所以当前 authority 已闭合为:
text
Building+0x0E int8 CaptureEventId
<-> runtime Tile+0x150 int32owner-transition 路径会从 Tile+0x150 取 EventId 进入 FUN_00383AC8,随后清零该 runtime 槽。这个结论闭合的是原版读入、runtime 投影和回写关系,不自动开放 writer validity。
新增证据:
text
reconstruction/docs/btl_event_producer_and_execution_lifecycle_closure_v1_report.md
reports/btl_semantic_recovery/event_producer_and_execution_lifecycle_closure_v1/event_producer_and_execution_lifecycle_closure.json3. +0x00 TileId 与 Building owner 不能混为一谈
Building 通过 TileId 放置到地图 Tile,但 Building 存在并不证明该 Tile 一定有 Country owner。
当前 corpus 已观察到:
text
270 original Buildings are on ownerless Tiles因此:
- Building placement 与 Tile ownership 是两个独立域;
- 工具不能因为某 Tile 上有 Building 就自动补 owner;
- Building duplicate / occupied Tile 的完整原版 winner/lifecycle 仍有 Unknown,不授权自动去重或重排。
4. +0x06 CityFeatureId 与旧 Landmark 名称
当前 parser 使用 CityFeatureId,旧兼容 alias 曾使用 LandmarkType。
原版 definition/表现路径支持这是 CityFeature 类输入。Reference 主名称采用:
text
CityFeatureId旧 LandmarkType 可以作为搜索 alias,但不再作为更强的全局业务断言。
5. +0x08/+0x0A 是 type-dependent 参数
这两个 uint16 都是有效序列化输入,但不能给出一个覆盖全部 BuildingType 的单一业务名。
当前保守名称:
text
+0x08 UnlockOrFeatureId
+0x0A RewardOrParameter它们会根据 Building type / mode 进入不同 consumer。此前关于“初始城市资源清除来源”的旧 H6C 解释已经被 native consumer 否定;不能用该旧结论反向强行命名这两个字段。
因此当前状态为 Partial,写入保持 NoGo 直至 type matrix 闭合。
6. +0x14 不是一个普通布尔值
原版代码把 +0x14 拆成多个状态位。即使当前 corpus 某些 bit/组合稀少或全零,也不能:
- 把整个 byte 命名成一个 bool;
- 为修改一个已知 bit 覆盖其他 bit;
- 将未观察位清零。
Reference 统一名称:
text
PackedState14完整 bit mask 尚未闭合,状态 Partial。
7. +0x17 是 packed flags
+0x16 是可独立读取的 AirDefenceType;相邻 +0x17 不是简单第二个防空等级,而包含多个独立 flag。
因此:
text
+0x16 AirDefenceType Confirmed
+0x17 PackedAirDefenceFlags Partial高保真 writer 必须 mask-preserve 未知位。
8. +0x18..+0x1D Facility levels
已确认的独立 facility level:
| Offset | 类型 |
|---|---|
+0x18 | Factory |
+0x19 | Research |
+0x1A | Medical |
+0x1B | Airfield |
+0x1C | Missile |
当前原版 corpus 中这些字段的观察等级范围主要是 0..4,但这是观察范围,不是格式上限证明。
+0x1D
原版 parser 已确认:
text
NuclearLevel = raw[0x1D] & 0x07即 low 3 bits 是 Nuclear level。
但是高 5 bits 不是安全 padding;已有证据表明它们属于 active extension bits。因此正式字段仍写成:
text
PackedNuclearAndExtensionLevel而不是单纯 NuclearLevel 1-byte scalar。
9. +0x1E..+0x1F
当前 corpus 中这两个 tail byte 全零,但尚无足够证据证明:
- 它们永远不会在其他版本/模式出现;
- 它们是编译器 padding;
- 原版 writer 可以任意规范化。
所以仍为:
text
Unknown
Raw-preserve
NoGo write10. 当前 closure backlog
Building 剩余重点:
+0x08/+0x0A的完整 BuildingType × consumer matrix;+0x10health/stage 的全部类型语义;+0x12/+0x13;+0x14全 bit mask;+0x15;+0x17全 bit mask;+0x1D高 5 bits;+0x1E/+0x1F;- 同 Tile Building duplicate 的构造 winner、失败对象生命周期和删除行为。
这些 Unknown 不影响 0x20 Building record 的物理 round-trip。