Files
mtgodot-poc/audit/contracts/resource.pack-locale-proto.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

13 KiB
Raw Blame History

resource.pack-locale-proto

Scope

比较 40250 的 EterPack 文件查找/覆盖、路径归一化、缓存、locale 编码、Python pack.Get/Exist、item/mob proto、MSM/MSA 和当前端资源入口、失败回退及测试证据。

Reference call chain

  • EterPack/CEterPackManager::Get
    • SEARCH_FILE_FIRST / pack-first 选择 loose file 或 pack。
    • ConvertFileName 统一小写、反斜杠为 /,以 CEterFileDict 的 CRC/name 映射 pack。
    • GetFromPack 支持根包、目录包、静态缓存和 pack overlay。
  • EterPack/CEterPackCursor
    • 对 pack 内数据提供有边界的 Read/Seek/Size
  • UserInterface/PythonPackModule.cpp
    • pack.Exist 查询虚拟路径。
    • pack.Get 只对 .py/.pyc/.txt 返回原始字节,其余失败。
  • EterLocale/StringCodec.cpp 及 locale 变体
    • 按 locale code page 处理非 UTF-8 文本,再交给 Python/UI。
  • GameLib/ItemManager.cpp::LoadItemTable/LoadItemList/LoadItemDesc
    • 从 EterPack 获取 MIPT/MIPX item proto、文本 item list 和 itemdesc;检查 fourcc、version、stride、数据尺寸及记录合法性。
  • UserInterface/PythonNonPlayer.cpp::LoadNonPlayerData
    • 从 EterPack 获取 MMPT mob proto,检查 fourcc、解压尺寸和记录。
  • GameLib/RaceDataFile.cppUserInterface/PythonSkill.cpp
    • 通过资源管理器加载 MSM/MSA、动作列表、技能和模型依赖。

Current call chain

  • project/asset_root.gd / project/asset_pack.gd
    • loose assets/、Godot assets.zip/PCK 和 asset_index.txt 是主运行时资源入口。
  • formats/asset_resolver.cpp
    • 扫描目录或装载 MTIDX1 索引;按固定一级目录优先级和 ymir work/ 后缀选择路径。
  • extension/src/pack/eterpack.cpp / pack_mount.cpp / asset_source.cpp
    • 实现当前 fork 自定义 XChaCha20 + Zstd .epk,并提供 loose/pack 读取和缓存抽取;目前没有被 GameScene/AssetRoot 主链调用。
  • extension/src/proto/proto.cpp / proto_node.cpp
    • 读取 MIPX/MIPT/MMPT、CLZO 和 proto key,建立 item/mob 索引。
  • project/locale.gd
    • locale/locale/<lang> 直接用 Godot FileAccess 读取 4 个文本表及 item/mob names;缺失表静默保留空字典。
  • formats/msm.cppformats/msa.cppformats/textscript.cppformats/combo_table.cpp
    • 解析动作、模型和脚本格式,测试覆盖合成输入及部分真实资源。

Audit findings (2026-09-20)

已对齐的部分

  • proto.cpp 已支持 40250 实际使用的 MIPX/MIPT/MMPT fourcc、版本/stride/element 边界、CLZO 解压和 item/mob 固定字段;item values[3]、specular、mob type/rank/level 等调用方字段已有测试。
  • AssetResolverPackMount 都处理大小写/斜杠、d:/ymir work/ 后缀和后挂 pack 覆盖;MSM/MSA、文本脚本和连击表已有格式级回归。
  • locale、proto、MSA/MSM 资源都已经从当前 assets 目录进入游戏场景的不同子系统,缺少资源时多数调用方有明确 fallback。

材料差异

  • 40250 的主资源权威是 CEterPackManager,而当前主运行时是 loose/assets.zip/Godot PCK + AssetResolverAssetSource/PackMount 目前没有被 AssetRootMetin2World、模型、音频和 UI 统一调用;因此“实现了 pack reader”不等于“游戏实际按 40250 pack 优先级加载”。
  • 当前 EterPack 使用 fork 自定义的 XChaCha20 + Zstd 单文件格式,40250 CEterPack 使用其原有 pack header/index/压缩/加密/策略链;两者不能互读。它是明确的平台/格式替换,不是已证明等价的适配。
  • 40250 的 SEARCH_FILE_FIRST/pack-first、根包与目录包、CRC 字典、静态缓存、文件覆盖优先级和 pack 内失败语义没有在统一运行时入口中闭环;AssetResolver 的固定目录 rank 不能直接证明与所有 40250 pack 注册顺序一致。
  • EterLocale 按 code page/locale 变体转换文本;当前 locale.gd 直接按 UTF-8 FileAccess 读取。中文 assets 目前可用,但 CP125x、Vietnamese、Arabic、Japanese 等路径和异常字节行为没有等价证明。
  • locale.gd 只加载 locale_interface.txtlocale_game.txtitemdesc.txtskilldesc.txt 及两个 names 表;40250 的 Python/locale 系统会按功能继续读取 jobdesc、empire、insult、guild、地图和 UI 路径等资源。各调用方自行拼路径,缺表时容易静默退化为 key/空值。
  • proto 当前单独由 GameScene 直接拼 assets_root/locale/... 文件路径加载;当资源只存在于当前自定义 pack 或 Godot PCK 内且没有解出到真实文件系统时,Metin2Proto/SkillTable/Locale 不共享同一虚拟读取器,可能出现 proto/文本/模型“一部分能读、一部分找不到”。
  • 40250 CItemManager::LoadItemTableCPythonNonPlayer::LoadNonPlayerData 的具体错误分支和记录尺寸校验较完整;当前 proto_node 失败后只写 last_error 并由上层继续使用空表,ItemManager 的“阻止未知 vnum/缺记录”语义还没有全部接到物品/模型入口。
  • MSA/MSM 格式解析已有较强测试,但资源失败时当前部分视图使用动作别名、目录文件 fallback 或胶囊/占位模型;这些是可见行为替换,不能仅凭解析测试宣称与 40250 的 CResourceManager 失败/保留当前动作语义一致。

Equivalence matrix

项目 状态 备注
Preconditions PARTIAL 文件/pack/proto 存在性和尺寸有检查;统一虚拟资源入口及编码前置未闭合
Branch structure PARTIAL loose/pack、proto fourcc、MSA/MSM 主分支已定位;搜索模式、locale 变体、失败回退未全对齐
Algorithms/formulas PARTIAL proto 字段/CLZO 和路径归一化已对齐;pack 格式、CRC/cache 和目录优先级不等价
State transition order PARTIAL GameScene 资源初始化顺序已定位;pack mount→proto→UI/model 的统一顺序无证据
Constants/units PARTIAL proto stride/offset 和 pack name field 有测试;code page、压缩/加密参数属于不同格式
Timing/event sources PARTIAL 当前同步加载与 AssetResolver 索引存在;40250 的 pack cache/lazy mapped read 未闭环
Resource/data sources PARTIAL MIPX/MMPT/MSA/MSM 可读取;主链仍可能绕过 PackMount,locale 编码和完整资源集合不足
Protocol side effects MAPPED 该合同主要是本地资源,不产生网络协议副作用;proto 失败对物品/实体的上层影响仍属 remaining
Interruption/failure/cleanup PARTIAL 单个读失败有错误返回;切换 locale、pack 重载、cache 失效和资源部分失败清理未完整证明

Regression evidence

  • extension/tests/pack_roundtrip_test.cpp:当前自定义 .epk 的加密/压缩、路径归一化、ymir suffix 和 patch 覆盖。
  • extension/tests/proto_test.cppextension/tests/proto_item_layout_test.cpp:真实/合成 item_proto、mob_proto、stride 和字段偏移。
  • formats/tests/msm_test.cppformats/tests/msa_test.cppformats/tests/combo_table_test.cppformats/tests/map_formats_test.cpp:格式解析与真实资源样本。
  • project/test_chinese_locale.gdproject/skill_test.gdlocale 和技能文本 smoke test。

project/package_render_test.gd 未计入本轮通过证据:它要求导出包的 MT_TEST_MODE=render 入口,直接用 godot --headless --script 不会复现该生命周期。

Deep audit round 2026-09-21

Fresh regression results

  • pack_roundtrip_testproto_testproto_item_layout_testformats_map_testformats_msa_testformats_msm_testformats_combo_table_test 均退出码 0;proto live 文件缺失时按测试设计跳过,formats live A1 在未设置 M2_ASSETS 时跳过。
  • test_chinese_locale.gd 16/16、skill_test.gd 通过;中文角色、怪物、物品和技能文本可读取。
  • package_render_test.gd 在直接 godot --headless --script 入口未能结束,和合同中要求的导出包 MT_TEST_MODE=render 生命周期不一致,不能计为通过。

Static parity conclusion

  • 当前自定义 .epk、proto 和路径归一化测试通过,但主运行时仍以 loose/assets.zip/PCK + AssetResolver 为主,PackMount/AssetSource 没有统一接入模型、音频、UI、proto 和 locale 主链。
  • 自定义 XChaCha20+Zstd .epk 不能互读 40250 原生 EterPackpack-first/search order、CRC 字典、cache overlay 和失败回退仍不是同一实现。
  • 中文 UTF-8 路径可用,但 EterLocale code page/异常字节/完整功能文本表和 proto/模型共享虚拟读取器仍缺等价证据;缺资源时部分入口继续用空表/占位/动作别名。

本轮仍为 PARTIAL,完成资源、pack、locale、proto 第二轮证据登记,未修改实现。

Active EterLib resource-core review

  • EterLib/Resource.cppCResource 通过 CEterPackManager 加载、重载、清理和错误回退;ResourceManager.cpp 维护资源缓存、CRC、后台加载、资源 map、延迟删除和 Update 生命周期;FileLoaderThread.cpp 将读取请求、取数和处理拆成线程阶段。
  • TextFileLoader.cpp/parser.cpp 提供缓存模式、token/group 解析和带类型的 token 读取,和当前仅按 FileAccess 读文本的路径不是同一失败/缓存/异步语义。当前已有格式和 .epk 单元测试,但没有证明主运行时的模型、音频、UI、proto、locale 都经过同一个资源管理器。
  • 因此本轮将上述 EterLib 活跃文件归入资源合同的静态源码证据;缓存命中、CRC 失败、后台加载取消、延迟删除和 typed-token 错误分支仍未在当前端形成等价实现,合同继续为 PARTIAL

Active EterPack/EterLocale/GameLib resource review

  • EterPack/EterPack.h/EterPackManager.h/EterPackCursor.h 明确了 EPKD v2 header/index、filename CRC 字典、root/dir pack、SEARCH_FILE_FIRST/SEARCH_PACK_FIRST、静态 cache、mapped read、读写/删除/Extract 和 pack policyEterPackPolicy_CSHybridCrypt.h 还定义 Camellia/Twofish/XTEA、每文件 key、SDB 和密钥流生命周期。当前自定义 XChaCha20+Zstd .epk 不能互读这套格式。
  • EterLocale/CodePageId.h 覆盖 CP874/932/936/949/950/1250-1258/65001StringCodec.h、Vietnamese/Arabic/Japanese 头文件分别暴露 code-page 转换、越南语编解码、阿拉伯语 shaping 和 Shift-JIS lead/trail/比较规则。当前 locale 以 UTF-8 FileAccess 为主,没有这些非 UTF-8/RTL/Shift-JIS 分支。
  • GameLib/Property*ItemManager.hRaceManager.hRaceMotionData.h 连接 property CRC、物品/种族/动作资源到 pack;当前 proto/MSM/MSA 格式能读不等于完整 CPropertyManager/CRaceManager/CItemManager 资源注册链已一致。
  • 本轮完成 EterPack、EterLocale 和 GameLib 资源声明/生命周期静态核对,合同保持 PARTIAL

Active EterLib image/font resource review

  • EterLib/Util.cppLoadTextData/LoadMultipleTextData 直接通过 CEterPackManager 读文本;同一文件还依据 code page 选择 charset/font face。TargaResource.cppJpegFile.cppGrpImage.cpp/GrpImageTexture.cpp/GrpSubImage.cpp 负责从资源字节到图像、纹理、子图和 GPU 纹理的 load/clear 生命周期。
  • GrpDIB.cpp/DibBar.cpp/BlockTexture.cpp 是 Windows DIB 到分块纹理的路径,涉及 clip、invalidate、锁定/解锁和最大纹理尺寸;当前 UI/资源侧使用 Godot ImageTexture/atlas,缺少 DIB/分块上传、纹理丢失重建及 pack 失败分支的等价证据。
  • 本轮完成 EterLib 文本/图像资源活跃文件静态核对;当前格式解析通过不等于 CResourceManager→图像纹理→UI 的同一资源和清理链,合同继续为 PARTIAL

Active UserInterface locale/font bridge review

  • UserInterface/Locale.cpp/.hLocale_inc_* 通过编译期区域选择 code page、字体、语言、地图/货币/日期和功能开关;GameType.cppDefaultFont_Startup/Cleanup/ReloadDefaultFontsCResourceManager 重载默认/斜体字体,SetGuildSymbolPath 参与会徽资源入口。
  • 当前 locale.gd 以运行时 lang/UTF-8 文本表为主,中文路径可用,但没有编译期 locale 变体、code-page 字体选择、默认字体资源重载和 locale-specific feature flags 的同一来源。
  • 本轮完成 UserInterface locale/font bridge 静态核对;资源合同继续为 PARTIAL

Status

PARTIAL。proto 和多种格式读取已经有较好基础,但当前运行时资源主链、40250 EterPack 格式/优先级、locale 编码、完整失败分支和统一虚拟读取入口尚未达到一致实现。