Files
metin2-client/docs/AVA2-SWITCHBOT.md
shenleiandClaude Opus 5.5 a22c064587 Add attribute lock buttons to the switchbot window
Five per-slot toggles next to start/stop, shown only when the server
sends the MTSB1 lock line; locked attributes are marked in the current
attribute line. Server side: metin2-server docs/FEATURE-ATTR-LOCK.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:06:00 +09:00

6.2 KiB
Raw Permalink Blame History

AVA2 自动洗练适配进度(v1 + 属性锁定)

2026-10-15。修改了 metin2-client 和 metin2-server,AVA2 代码只作参考。服务端规则和协议见 metin2-server/docs/FEATURE-SWITCHBOT.md。

与 AVA2 的差异

项目 AVA2 本实现
窗口 新增 SWITCHBOT 物品窗口,5 个物品槽加 1 个道具槽 不新增窗口类型,物品留在背包,按物品 ID 绑定;每个角色同一时间只洗 1 件
洗练执行 自己实现消耗和 ChangeAttribute,绕过手动检查和 ItemLog 每次都调用原 UseItem,检查、概率、日志、扣道具都和手动洗练一样;71151/76023 仍只能洗等级上限 ≤40 的武器和衣服
速度 0.1 秒一次 0.25 秒一次(约 4 次/秒)
物品被移动 拦截移动、交易、出售等路径 每次洗练前重新检查:物品不在背包、已装备、易主时停止(item_gone);交易、商店、仓库、合成界面打开时停止(busy)
换线 / 下线 通过 P2P 转移,继续洗 直接停止,不离线洗练

匹配规则和 AVA2 相同:最多 2 套方案,每套 1–5 条“属性 ≥ 阈值”;任意一套全部达标就停止,只看前 5 条普通属性。

客户端

  • 模块 mt_switchbot(src/platform/ScriptLib/SwitchbotScript.inc),在 PythonBoot.cpp 中安装。入口是小地图旁“百科”按钮下方的“洗练”按钮。
  • 物品:扫描背包里至少有一条属性的武器和防具,用 < > 切换。洗练道具:扫描子类型为 USE_CHANGE_ATTRIBUTE 的道具,显示数量。次数上限可选 10、50、100、200、500、1000。
  • 可选属性和最大值由服务端 attrs 下发,客户端不自己推算。添加属性时分页点选;阈值用 -/+ 调整,步长为最大值的 1/5,默认取最大值。
  • 运行时锁定所有设置,实时显示次数、剩余道具、停止原因和当前 5 条属性。停止时在聊天框提示;达标时如果窗口已关闭,会自动打开。
  • 命令间隔至少 0.3 秒,同一时间只有一个请求在等待回复。4 秒没有回复就显示“服务器尚未启用自动洗练”。attrs 只接受完整、连续的回复,不完整的整批丢弃。
  • 文字都用 GBK 可编码的字符(不用 ◀/▶/⚠)。

属性锁定(2026-10-15)

  • 服务端规则、存储和协议见 metin2-server/docs/FEATURE-ATTR-LOCK.md。锁定的槽位在所有洗练方式下都保持不变:手动用道具、自动洗练、GM 命令。
  • 窗口底部“开始/停止”右边有 5 个按钮,每条有属性的普通槽一个:锁N 表示未锁,【锁N】 表示已锁。点击切换。选属性时和洗练中不能点。
  • 当前属性行里,已锁的属性前面加 [锁]。状态行提示“已锁定的属性在每次洗练中保持不变”。
  • 服务端在 attrs_end 之后下发 MTSB1 lock CELL VNUM MASK。旧服务端不发这一行,所以不显示按钮。
  • 错误提示:slot(该条属性不能锁定),max(最多锁定 2 条,且至少留 1 条可洗),db(保存失败)。
  • 与 AVA2 的差异:
    • 锁定免费。AVA2 每次锁定或解锁消耗 50348/50349,203 的 item_proto 里没有这两个道具。
    • 锁定状态存在服务端独立表里,不占属性槽。
    • 不要求物品正好有 5 条属性,但至少要留 1 条不锁。
  • 联机测试(channel5 13040,盔甲 11209,背包 19 格):
    • 锁第 2、4 条后,自动洗 10 次,这两条每次都不变,其余 3 条每次都变;
    • 锁第 3 组时提示 max;
    • 重新登录后锁定状态仍在;
    • 解锁后表里的行被删除。

证据

  • tests/wiki/test_switchbot.py(CTest:port.switchbot)共 7 项通过(第 7 项是锁定协议和按钮),覆盖:
    • 请求节流和合并;
    • 不完整的 attrs 回复被拒绝;
    • start 命令的拼装和校验;
    • state/error 解析和超时;
    • 和服务端的原因码、错误码、上限一致;
    • 窗口流程:扫描 → 读取属性 → 选属性 → 开始 → 达标提示。
  • 脚本能在 Python 2.7 下编译。tests/wiki/test_service.py 仍然通过。
  • 2026-10-15 联机测试(203 额外开的测试核心 channel5/first,端口 13040,使用隔离编译的 game;macOS 原生客户端,账号 admin,物品为背包 33 格的剑 279,道具 71084):
    • 上限 10 次:洗满 10 次后停止(limit),约 4 次/秒。
    • 两套方案、阈值 1:第 18 次达标(matched)。
    • 已经达标的物品:0 次就停止,不扣道具。
    • 洗练中把物品从 33 格移到 90 格:继续洗,窗口跟到 90 格;点停止后显示 stopped。
    • 洗练中退出客户端:服务端立即停止。
    • log.log 中 CHANGE_ATTRIBUTE 共 72 行,和总次数一致。
    • busy:洗练中摆摊(先给 50200 摊位包袱;没有它 OpenMyShop 会提前返回、摊位不会开,第一次测试就是这样误判的),摊位开出约 1 秒后停止(busy),共洗 6 次。
    • no_scroll:用 76014(共 6 张)、上限 10,洗 6 次后停止(no_scroll),道具剩 0。
    • rejected:对 90 级剑用 71151(原路径只允许等级 <= 40):0 次就停止(rejected),道具未扣。
    • 截图里窗口布局正常。仓库自带的 Client 是英文 cp1252 locale,所以中文显示为 ????;需要 zh locale 客户端才能看到中文。
  • 联机测试发现并修复了两个窗口问题,test_switchbot.py 已加回归用例:
    • 洗练中移动物品后,选中项会跳到别的物品:现在按服务端报告的格子跟随。
    • 空闲时移动物品后选中项丢失:现在退而按相同 vnum 匹配。
  • 服务端 tests/features/test_switchbot.py 和 test_queries.py 通过。203 的隔离目录 /root/metin2-features-dev 完整编译通过。

未完成

  • Android 真机测试。
  • macOS 构建需要 -DMT_40250_SOURCE=<含 EterPack/EterPack.cpp 的源码目录> 来生成 pack 密钥,否则 system.py 读不出来(RunMain Error)。本机没有 40250 源码,这次用的是 AVA2 的 TEST/3. Source BIN/Client,两者密钥相同。
  • 服务端还没有部署到 203 正式环境。
  • 属性锁定已完成(见上),尚未部署到正式环境。