layout: restructure into src/ tests/ android/ scripts/ tools/

- extension/src/{port,platform,codepage} -> src/; native_render -> src/host
  (+ dxt, shaders/); libgr2 -> src/gr2; extension/third_party -> third_party
- extension/tests -> tests/port, libgr2/tests -> tests/gr2
- android-native -> android (build.sh, push-client.sh moved in)
- script -> scripts; tools/40250 -> tools/server; oracle -> tools/granny-oracle;
  perf tools -> tools/perf
- all build trees under build/ (native, release, android, port-gate)
- xrender:: CMake aliases -> mt::; port-map ledger impl paths rewritten

No code changes. ctest 15/15, port_gate macos+android PASS, port_map check 0 errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-29 19:08:19 +09:00
co-authored by Claude Opus 5.5
parent 70710477cf
commit a46093104c
2817 changed files with 13728 additions and 13744 deletions
+17 -17
View File
@@ -260,7 +260,7 @@
switch(`FUNC_WAIT` 1.0 阈值、`FUNC_COMBO/ATTACK/MOB_SKILL` 50.0 阈值 + `m_kMovAfterFunc`
到达后动作、`skip_collision`);释放门按 `m_server_frame_ms`(新 `set_server_frame_ms`,
为 0 时立即释放 = 旧行为)+ `__CanProcessNetworkStatePacket`(dead / knock_down hold
队列)。`tick()` 每帧先 `process_states()`。新增 `extension/tests/net_state_queue_test.cpp`;
队列)。`tick()` 每帧先 `process_states()`。新增 `tests/port/net_state_queue_test.cpp`;
`net_entity_test` 的 `FUNC_ATTACK` 断言按新语义改写;C++ 20/20 + GDScript 回归全绿。
留给增量 78:net_play.gd 上行 6 事件回调 + 节流常量、net_world.gd 去掉自有 lerp、
从 `GC_HANDSHAKE` `lDelta` 接真实服务器帧钟。
@@ -884,7 +884,7 @@
| 工作流 | 负责条目 | 主要修改范围 | 不得越界修改 |
|---|---|---|---|
| W0 公共基础 / 集成 | §0、共享会话、实体接口、场景生命周期、文档 | `extension/src/net/m2_client.*`、`entity_store.*`、`classic_session.*`、`project/game_scene.gd`、两份差距文档 | 其他工作流不得各自复制网络核心或场景 reset;接口改动必须回 W0 |
| W1 协议 / 账号 | §1、Classic wire / parser、登录、选人、DirectEnter、断线 | `extension/src/net/classic/*`、`extension/tests/net_classic_*`、登录 / 选人专属脚本 | 不直接重写 W0 的公共信号和 EntityStore 生命周期 |
| W1 协议 / 账号 | §1、Classic wire / parser、登录、选人、DirectEnter、断线 | `extension/src/net/classic/*`、`tests/port/net_classic_*`、登录 / 选人专属脚本 | 不直接重写 W0 的公共信号和 EntityStore 生命周期 |
| W2 实体 / 世界 / 战斗 | §2–§3、移动、动作、技能、目标和换图后的实体表现 | `project/net_world.gd`、`net_play.gd`、`player_controller.gd`、`project/world/*`、动画 / 战斗扩展和测试 | 不把 UI 状态写入协议层;共享 reset 只通过 W0 接口接入 |
| W3 玩法 UI / 输入 | §4–§5、§8、背包、任务、社交、IME、键位 | `project/ui/*`、`hud.gd`、`login.gd`、`charselect.gd`、UI 测试和本地化资源 | 不修改 Classic parser;缺少真服时使用 fixture,并注明未验证 |
| W4 渲染 / 资产 / 音频 | §6–§7、§9、模型、特效、地图、材质、天气、BGM、生命周期表现 | `extension/src/{gr2_bridge,metin2_world,terrain_splat,m2_material,environment_builder}.*`、`project/fx/*`、音频 / 渲染专属脚本和测试 | 不把渲染 fallback 塞进网络状态机;场景钩子由 W0 提供 |
@@ -1392,14 +1392,14 @@ return true;
作为 follow-up。
3. ⬜ **不在本批次**:`charselect.gd` / `guild_creation_ui.gd` 的名字长度校验统一为
`<= 24` 字节属 GDScript(W3 / Phase 2);本批次只交付 C++ 侧编码。已在下方登记。
4. ✅ 回归:新增 `extension/tests/net_text_codec_test.cpp`(`ctest` `net.text_codec`),
4. ✅ 回归:新增 `tests/port/net_text_codec_test.cpp`(`ctest` `net.text_codec`),
覆盖 CJK 名恰好 24 字节(接受)、25/27 字节(截断到 24,绝不 25/26)、
多字节边界截断(切进 3 字节序列中间丢整字)、ASCII 往返、`from_wire_str` 遇 NUL 停 /
悬空前导字节裁除 / 无终止符满字段整读。`extension/CMakeLists.txt` 注册。
**W1 增量 50 已落地(🔎 待真实验收)**
- 改动:`extension/src/net/text_codec.h`(新)、`extension/tests/net_text_codec_test.cpp`(新)、
- 改动:`extension/src/net/text_codec.h`(新)、`tests/port/net_text_codec_test.cpp`(新)、
`wire_classic.h`(include)、`classic_session.cpp`(8 处 to_wire 路由)、
`classic_parser.cpp`(ADDITIONAL_INFO from_wire_str)、`extension/CMakeLists.txt`(测试注册)。
- 测试:`ctest` `net.text_codec` 通过(新增,套件 16 → 17);`net.classic_session` 通过。
@@ -1966,7 +1966,7 @@ affect 图标与剩余时间没有统一状态。
时 hold 队列不丢包)。走路时长优先用服务器 `dur_ms`(≈ `SNetworkActorData::UpdatePosition`
的插值窗口),缺省才按 `dist / moving_speed` 推。
- `tick()` 每帧先 `process_states()` 再推进插值。
- 回归:新增 `extension/tests/net_state_queue_test.cpp`(帧钟释放门、帧钟 0 立即释放、
- 回归:新增 `tests/port/net_state_queue_test.cpp`(帧钟释放门、帧钟 0 立即释放、
`FUNC_WAIT` 1.0 阈值、`FUNC_COMBO` 50.0 阈值 + 到达后动作、knock_down / dead hold 门、
多条到期命令一次排空按序);`net_entity_test` 的 `FUNC_ATTACK` 断言按新语义改写
(近距 <50 瞬移+动作、远距 ≥50 先走后打)。C++ 20/20(含新 `net.state_queue`)、
@@ -2717,7 +2717,7 @@ main->IsFishingMode() → OnCannotUseSkill("REMOVE_FISHING
隐式转换后再截断。
3. ✅ 按参考语义保留必要特殊值:`set_target(0)` 清目标、`shop_sell(count=0)` 选择旧版单件包、
`move_item(count=0)` 保留整堆语义;没有用“把负数改成 1”掩盖调用方错误。
4. ✅ 回归:新增 `extension/tests/net_bounds_test.cpp` / CTest `net.bounds`,覆盖每个共享边界的
4. ✅ 回归:新增 `tests/port/net_bounds_test.cpp` / CTest `net.bounds`,覆盖每个共享边界的
端点与越界值;`cmake --build build/extension -j2` 通过,`ctest --test-dir build
--output-on-failure` 为 18/18。相关 Godot 离线回归(`netbridge_test`、`p8_test`、
`shop_cube_mall_test`、`guild_refine_test`、`dragon_soul_test`、`guild_mark_test`、
@@ -5594,7 +5594,7 @@ dx² + dy² > s_fLimitDistance → 不播
project/ui/shop_ui.gd —— 实例 / 原型 `ANTIFLAG_SELL`、`IsValuableItem` 首次确认、
普通 / `Is1GoldItem` 售价公式和失败音效;
project/ui/private_shop_ui.gd —— `ANTIFLAG_GIVE/MYSHOP` 拦截;
extension/tests/proto_item_layout_test.cpp、project/shop_rules_test.gd —— 新增布局 / 出售规则回归。
tests/port/proto_item_layout_test.cpp、project/shop_rules_test.gd —— 新增布局 / 出售规则回归。
测试:`cmake --build build/extension -j2`、`ctest --test-dir build/extension --output-on-failure`;
`inventory_ui_test.gd`、`mouse_controller_test.gd`、`p8_test.gd`、`shop_rules_test.gd`、
`private_shop_ui_test.gd`、`complex_item_drop_test.gd` 均通过。
@@ -5636,7 +5636,7 @@ dx² + dy² > s_fLimitDistance → 不播
对齐武器攻击 / 魔攻、防具防御公式、限制、applies、属性、魂石孔和精炼关联;
project/ui/inventory_ui.gd、view_equipment_ui.gd、shop_ui.gd、safebox_ui.gd、mall_ui.gd、
exchange_ui.gd、private_shop_ui.gd —— 接入同一个提示构造器;
extension/tests/proto_item_layout_test.cpp、project/item_tooltip_test.gd —— 锁定布局和提示内容。
tests/port/proto_item_layout_test.cpp、project/item_tooltip_test.gd —— 锁定布局和提示内容。
测试:`cmake --build build/extension -j2`;C++ CTest 全套(首次 `net.classic_encstream` 瞬时失败,
定向重跑通过,需在集成前再重跑全套);`inventory_ui_test.gd`、`item_tooltip_test.gd` 通过。
验收:未验证——鱼竿 / 镐经验、龙魂计时、技能书 / 变身特殊分支、装备对比、CJK / 真 `.sub`、
@@ -5758,7 +5758,7 @@ dx² + dy² > s_fLimitDistance → 不播
extension/src/net/net_bounds.h(新)——窄整数、快捷栏 / 商店 / 私人商店 / 交易 / Cube / 龙魂 / 点数组边界
extension/src/net/m2_client.cpp —— 连接端口、角色创建、聊天 / 技能 / 社交 / 商店 / 仓库 / 私人商店 /
Cube / 公会 / 精炼 / 物品操作在 static_cast 前统一拒绝溢出和非法 Variant;移除静默截断 / 负数归一化
extension/tests/net_bounds_test.cpp(新)、extension/CMakeLists.txt —— CTest net.bounds
tests/port/net_bounds_test.cpp(新)、extension/CMakeLists.txt —— CTest net.bounds
测试:cmake --build build/extension -j2 通过;ctest --test-dir build --output-on-failure → 18/18;
Godot 离线回归按独立 --log-file 串行执行,受影响脚本均 exit 0 且输出 PASS。无新增 skip。
验收:未验证——无真实 40250 服务端的完整业务包回执;Godot 测试中的 macOS 证书探测 / 资源释放提示
@@ -5814,7 +5814,7 @@ dx² + dy² > s_fLimitDistance → 不播
其余 npclist 命名 + mut_spawn);GC_CHAR_ADDITIONAL_INFO(无 pending → m_last_error +
drop;命中 → 合并 9 字段 + mut_spawn_full + erase);ADDITIONAL_INFO 名字读 from_wire_str
extension/CMakeLists.txt —— string(TIMESTAMP)→MT_BUILD_TIMESTAMP 定义;net.text_codec 测试注册
extension/tests/net_text_codec_test.cpp(新)、net_classic_session_test.cpp(版本断言 +
tests/port/net_text_codec_test.cpp(新)、net_classic_session_test.cpp(版本断言 +
两包合并断言重写)
接口/数据结构变化:ClassicSession +2 setter +2 成员;ClassicParser +2 public 方法
+1 private 方法 +3 私有成员(m_npclist_path / m_npc_names / m_npc_names_loaded);
@@ -5857,7 +5857,7 @@ dx² + dy² > s_fLimitDistance → 不播
Entity 创建,find-or-return;mut_char_update() guild/alignment/pk_mode 变化也推 {Info};
+mut_affect_flags(vid,lo,hi)(v=lo|(hi<<32),变化则 m_dirty);+匿名 dbg_ignored 助手
extension/src/net/entity_store.h —— +mut_affect_flags 声明
extension/tests/net_entity_test.cpp —— +§2.1 数据层断言块(远端 ADD 填行+入队 Spawn、
tests/port/net_entity_test.cpp —— +§2.1 数据层断言块(远端 ADD 填行+入队 Spawn、
UPDATE 改写、未知 VID 五个 mut_* 既不建行也不缓存)
project/net_world.gd —— +CHAR_STAGE_VIEW_BOUND/AFFECT_SHOW_ALWAYS/WALL_RACES 常量;
+_update_visibility()(每帧 __IsVisibleActor 判定,建/淡出节点,_fading 防抖);
@@ -5983,7 +5983,7 @@ dx² + dy² > s_fLimitDistance → 不播
project/ui/quest_dialog.gd —— 识别 COLOR/COLOR256、ITEM/MOB、WINDOW_SIZE、居中、CONFIRM_WAIT、
IMAGE/TITLE_IMAGE 元数据和 DELAY/WAIT;game_scene.gd 传入 proto / assets_root;
project/ui/friend_ui.gd —— 确认框答复后主动隐藏,避免连续模态框残留;
extension/tests/net_entity_test.cpp、net_classic_session_test.cpp、project/quest_test.gd ——
tests/port/net_entity_test.cpp、net_classic_session_test.cpp、project/quest_test.gd ——
交易 sockets/attrs、任务标签、任务时钟回归。
测试:`cmake --build build/extension -j2` 通过;`ctest --test-dir build/extension -R
'net.entity|net.classic_session' --output-on-failure` 2/2 通过;`p8_test.gd`、`item_tooltip_test.gd`、
@@ -6452,10 +6452,10 @@ dx² + dy² > s_fLimitDistance → 不播
duration, arg, time)`。
extension/src/net/classic/classic_parser.cpp —— HDR_GC_MOVE:`mut_move(vid,
rot*5.0f, func, x, y, duration, arg, time)`。
extension/tests/net_entity_test.cpp —— 旧 FUNC_ATTACK 贴齐单测拆成「近」(dir_len
tests/port/net_entity_test.cpp —— 旧 FUNC_ATTACK 贴齐单测拆成「近」(dir_len
30<50 → 贴齐 + `func==FUNC_ATTACK`)+「远」(dir_len 170>=50 → 先 `func==FUNC_MOVE`
走,`tick()` 后到达 Dst + `func==FUNC_ATTACK`)。
extension/tests/net_state_queue_test.cpp(新增,5 组)——① 服务器帧钟释放门(未来
tests/port/net_state_queue_test.cpp(新增,5 组)——① 服务器帧钟释放门(未来
chk_time 挂队;帧钟追上才释放;帧钟 0 立即释放);② FUNC_WAIT 1.0 阈值(贴齐 vs 走 +
after WAIT + skip_collision);③ FUNC_COMBO 50.0 阈值 + 到达后动作 + arg 锁存;
④ `__CanProcessNetworkStatePacket` 门(knock_down / dead 挂队,恢复即释放;未知 vid 不崩);
@@ -6557,11 +6557,11 @@ dx² + dy² > s_fLimitDistance → 不播
· `drain_state_queue` 帧钟门改为:`m_server_frame_ms != 0 && chk_time >
m_server_frame_ms && chk_time - m_server_frame_ms <= STATE_QUEUE_MAX_WAIT_MS`
才 break;超过 cap 的领先量当异帧钟 `dwTime`,立即放行。
extension/tests/net_classic_stream_test.cpp ——
tests/port/net_classic_stream_test.cpp ——
· 新增「server frame clock (§3.2)」段:握手前 `server_frame_ms()==0` +
`!has_server_clock()`;喂一个 `hs.time=500000, delta=20` 的握手后
`has_server_clock()` 且帧钟 ∈ [500020, 505020);连读两次单调不减。
extension/tests/net_state_queue_test.cpp ——
tests/port/net_state_queue_test.cpp ——
· 新增第 6 段:`set_server_frame_ms(1000)`,`chk_time == 1000+cap` 仍 gated;
另一实体 `chk_time == 1000+cap+1` 立即放行(防呆阀边界)。
测试:`ctest --test-dir build` → 20/20(`net.classic_stream` / `net.state_queue` 覆盖新逻辑);
@@ -7090,7 +7090,7 @@ dx² + dy² > s_fLimitDistance → 不播
extension/src/net/m2_client.cpp —— use_skill(int skill_id, int target_vid)(形参增量 52 起即带符号)
护栏:skill_id <= 0 || !bounds::u32(skill_id) → !mtnet::bounds::skill_index(skill_id)
(target_vid 仍 >= 0 && bounds::u32;cast_skill() 的 motion_idx ∈ [0,0x7f] 不动)
extension/tests/net_bounds_test.cpp —— +4 CHECK(SKILL_MAX_NUM==255 / 端点 1、254 /
tests/port/net_bounds_test.cpp —— +4 CHECK(SKILL_MAX_NUM==255 / 端点 1、254 /
越界 0、255、-1 / 拒 0x7fffffff+1)
project/ui/skill_table.gd ——
· _load_cooltime → _load_msk(调用点 line 152),+解析 .msk NeedSPFormula → entry["need_sp_formula"]