版本:v1.2(2026-10-01) 状态:待评审(协议侧 T01-T12 已全定案) 路线:Headless 无客户端运行时(用户已确认)——不安装传奇游戏客户端,Python + Lupa(LuaJIT 2.1)直接跑游戏原版 Lua 逻辑,完成新手期 13 个任务 前置验证:本机已实证 ①Lupa 可嵌入 LuaJIT 2.1(与游戏引擎同款运行时)②游戏 netMessageDef.lua 原样加载成功 ③协议层(HTTP 登录+TCP 帧编解码+Encode6BitBuf+17 帧初始化+创角+喝药+心跳)在纯 Python 已全程跑通(2026-09-21 逐鹿05区实测) 协议定案索引(真机抓包):
protocol_bot/docs/探索总结-20261001-领锄头与挖矿全链路定案.md(T04/T05 最完整版)+协议定案-神通开启与五行之力.md(T10/T11/T04/T05)+ 各会话交接文档
git clone + pip install 即可运行lua脚本解密源码/mod_fgcq/stab/scripts/)的协议层与业务 Proxy,由 Python 提供 C++ 引擎绑定面的 stub┌────────────────────────── 目标机(任意 Mac/Linux,无游戏客户端)──────────────────────────┐
│ Python 宿主进程 (apilot) │
│ │
│ ┌─ HTTP 侧(已验证,复用 protocol_bot)────────────────────────────────────────────┐ │
│ │ login_996pc.py 极验滑块+RSA+BOXAPP签名 → JWT │ │
│ │ enter_game EnterGameClient → start_info(游戏侧票据) │ │
│ └──────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─ Lupa 嵌入 LuaJIT 2.1(与游戏引擎同款运行时)─────────────────────────────────┐ │
│ │ │ │
│ │ ┌─ 引擎 stub 层(Python 实现,规格=绑定面清单)────────────────────────┐ │ │
│ │ │ netClient: Connect/Disconnect/Send/Tick │ │ │
│ │ │ networkCtl(LuaNetworkController): SendMsg/RegisterLuaHandler │ │ │
│ │ │ Scheduler / Director(tick 驱动) / FileUtils / LuaBridgeCtl │ │ │
│ │ │ L_GameEnvManager(env 注入) / tolua.* / cc.*(no-op 子集) │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ │ ▲ stub API │ │
│ │ ┌─ 游戏原版 Lua(只读复用,不改一行)────────────────────────────────────┐ │ │
│ │ │ network/netMessageDef.lua(630 消息定义) │ │ │
│ │ │ network/networkUtil.lua(LuaSendMsg/SendTableToServer) │ │ │
│ │ │ framework/(PureMVC: Facade/Proxy/Mediator) │ │ │
│ │ │ game/proxy/remote/(LoginProxy/AuthProxy/SUIComponentProxy/…) │ │ │
│ │ │ util/ + cocos/cocos2d/functions.lua(class/handler/string扩展) │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ │ ▲ APilot API(铁律:任务只碰这层) │ │
│ │ ┌─ APilot 框架(我们新增的 Lua)────────────────────────────────────────┐ │ │
│ │ │ 核心: 事件总线 / 任务引擎(状态机+守护并行) / 调度 / 日志 / 配置 │ │ │
│ │ │ 任务: T01创角 T02弹窗 T03喝药 … T13活动(参数化模板) │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─ TCP 侧(已验证)───────────────────────────────────────────────────────────┐ │
│ │ socket ↔ 帧编解码(24B头+体) ↔ Encode6BitBuf ↔ sdata 加密因子 │ │
│ │ 收帧 → 解码 → 构造 msg 对象 → 回调 Lua RegisterLuaHandler 注册的 handler │ │
│ └──────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────────┘
│
▼ (真实网关 jycq-206923.dhsf.xqhuyu.com:80xx)
Lua 任务代码 → AP.send(msgId, table)
→ SendTableToServer(cjson 编码) → LuaSendMsg → networkCtl:SendMsg(stub)
→ Python: 组 24B 头(recog/param1/param2/param3)+体 → Encode6BitBuf → socket 发送
服务端回帧 → Python 收 → 解码头/体 → 还原 sdata 解密上下文
→ 构造 msg stub 对象{GetHeader()/GetData():ReadString()/GetDataLength()/GetMsgId()}
→ 调用 LuaRegisterMsgHandler 注册的 Lua handler → 游戏 Proxy 逻辑运行
→ PureMVC 通知 → APilot 事件总线 → 任务状态机推进
游戏内 GameWorldController:CheckHeartBeat() 依赖 update(delta) 帧循环。Headless 下由 Python 宿主循环驱动(50ms 一步,对齐真实引擎节奏):
while running:
netClient.Tick() # 处理收发队列
Scheduler.Tick(0.05) # 驱动 PerformWithDelayGlobal/Schedule 回调
time.sleep(0.05)
心跳本身复用游戏 gameWorldController.lua 的 10s 间隔逻辑(或 Python 侧直接发 CS60000,二选一,实现期定;倾向前者——同构)。
| 模块 | 职责 |
|---|---|
apilot/host.py |
宿主生命周期:启 Lua VM → 注入 stub → 驱动 tick 循环 → 优雅退出 |
apilot/bridge.py |
Lupa 桥:Python↔Lua 双向调用、类型转换、异常穿透 |
apilot/stubs/*.py |
绑定面 stub(见 §4):net_client / network_ctl / scheduler / env / tolua / cc_noop |
apilot/wire.py |
TCP 层(从 cq2_pure_enter.py/cq2_protocol_client.py 提炼):连接、帧编解码、Encode6BitBuf、sdata、收发队列 |
apilot/http_login.py |
HTTP 侧(复用 login_996pc.py + EnterGameClient) |
apilot/config.py |
账号/区服/任务清单配置加载 |
apilot/main.py |
CLI:apilot run --zone 14481607 --tasks T01,T03 |
apilot_lua/ 目录)| 模块 | 职责 |
|---|---|
apilot/init.lua |
框架引导:挂总线、注册守护、按配置装载任务 |
apilot/bus.lua |
事件总线:包装 PureMVC Facade,提供 AP.on(notice, fn) |
apilot/engine.lua |
任务引擎:顺序流水(状态机)+ 守护(并行常驻)+ 任务模板注册表 |
apilot/api.lua |
窄接口(铁律):AP.send / AP.on / AP.tick / AP.config / AP.log / AP.state |
apilot/guard_*.lua |
守护:掉线重连(60004/60005/60006)、心跳、异常回城 |
apilot/tasks/T01..T13.lua |
13 个任务模块(见 §5) |
铁律(与之前决策一致):任务代码只允许调用 AP.*,禁止直接碰 global.Facade/SendTableToServer/cc.*。APilot API 有且只有一个 HeadlessAdapter 实现——这条纪律使未来切换/复用运行时零成本。
只读复用,不修改:
network/netMessageDef.lua、network/networkUtil.lua、network/jsonproto/framework/(PureMVC 全套)game/proxy/remote/(LoginProxy/AuthProxy/SUIComponentProxy/ItemUseProxy/MissionProxy/AutoProxy/BagProxy/PlayerPropertyProxy/MapProxy/NPCProxy…按任务需要逐步启用)util/util.lua、cocos/cocos2d/functions.lua(class/handler/字符串表扩展)config/(ProxyTable/NotificationTable/mmoConstants/netMessageDef 依赖的常量)不复用(UI/渲染强绑定):GUI/、ssr/ssrengine/ 的渲染部分、game/mediator/ 的 UI Mediator、gamestates/ 的状态机外壳(其登录链逻辑由 stub+任务引擎替代驱动)、actor/animation/scene 渲染层、assets_downloader/(headless 不需要热更资源)。
注:PureMVC 的 UI 通知(如
Layer_Login_Role_Open)在 headless 中无人订阅 = 无害空操作,不需要屏蔽。
依据 explore 产出的绑定面清单(6 万字节,存于 tool-output,实现时逐项核对),分四类:
| 绑定 | 方法面 | Python 实现 |
|---|---|---|
netClient(C++ 单例) |
Connect(host,port) / Disconnect() / Tick() / Send(bytes) / SetNetMessageTypeSData(v) / GetNetMessageTypeSData() / IsConnected() |
wire.py 直通;Connect 真实 socket |
LuaNetworkController(networkCtl) |
Inst() / SendMsg(msgId, recog, p1, p2, p3, dataStr, dataLen) / RegisterLuaHandler(msgId, cb) / UnregisterAllLuaHandler() |
SendMsg→组帧发送;RegisterLuaHandler→Python 侧 handler 表,收帧后构造 msg 对象回调 |
| msg 对象(收包回调参数) | GetMsgId() / GetHeader()→{recog,param1,param2,param3,msgId} / GetDataLength() / GetData():ReadString(len)(+按需 ReadInt/ReadByte) |
每帧构造一个 Lua table-backed 对象 |
| 绑定 | 方法面 | 实现 |
|---|---|---|
cc.Director:getInstance() |
getScheduler() / getEventDispatcher() / getRunningScene()(返回 nil-safe 场景 stub) |
Python 计时轮 |
| Scheduler 面 | scheduleScriptFunc(fn, interval, paused) / unscheduleScriptEntry(id) |
同上 |
PerformWithDelayGlobal / Schedule / UnSchedule(若为 C++ 导出;清单核对) |
延时/周期回调 | 同上 |
LuaBridgeCtl |
Inst() / GetModulesSwitch(idx) / SetModulesSwitch(idx,v) |
dict 存储,返回合理默认(心跳开关=1) |
gameStateMgr |
Inst() / RegisterLuaHandler(cb) / ChangeAppState |
最小实现:转发给 APilot engine |
| 绑定 | 实现 |
|---|---|
L_GameEnvManager |
GetEnvDataByKey(k):从 start_info/env 注入的 dict 读取(uid/token/new_boxtoken/isBoxLogin=1/signkey/channel/gameid…)——这正是 SHBoxMacOS 凭证在客户端内的形态 |
cc.FileUtils:getInstance() |
getWritablePath()→本地 state 目录;isFileExist/getDataFromFile/writeStringToFile/fullPathForFilename→真实文件系统(限定根目录) |
gameEnviroment(注意小写 e,25 处引用) |
GetNetClient/SetLoginAccount/GetDownloadRootURL 等 5 方法面 → stub |
cc.Sprite/Node/Label/Layer/Scene/TextureCache/SpriteFrameCache/DrawNode/Action 系列、ccui.*、ccs.*、ccexp.AudioEngine/WebView、ScriptHandlerMgr、mouseEventController、frameAnimManager、tolua.cast/getpeer/setpeer(可返回原对象/空表)、bugly*、SetCusTomCursor、GUIFunction、JUMPTO、GET_STRING(返回 key 或空串)、GET_SETTING/CHECK_SETTING/CHANGE_SETTING(配置 dict)、CreateStaticUIModel、Encode6BitBuf(若 Lua 侧直接调——用 Python 已验证算法经桥返回;大概率登录串编码走此路)、UserData、socket.gettime(→os.clock)、release_print/releasePrint(→日志)。
实现策略:先做一个
__index万能 no-op 工厂(返回记忆化空表/空函数),再按绑定面清单把 4.1-4.3 的真实实现逐个覆盖。启动游戏 Lua 加载链时遇到的每个 nil 崩溃都是清单缺项的信号,补一个删一个。
任务引擎:顺序流水(T01→T13 可配置跳过/重排)+ 守护并行(掉线重连/心跳)。
| # | 任务模块 | 状态机要点(协议依据=《新手期13步任务实现思路》+已实测手册) | 完成判定 |
|---|---|---|---|
| T01 | t01_create_role.lua |
2001→529→104→530→100→520;空列表→107 要名→539→101 创角;522 重名→重试≤5 | 收 521 且角色入列表 |
| T02 | t02_dismiss_notice.lua |
等 767/6800/3215 弹窗通知(不阻塞后续任务,超时放行) | 超时 30s 或收到 SC50 |
| T03 | t03_potion_guide.lua |
CS3199 @openmianban,23 → @chiyao_kaiqi(index 109/303,已实测);可选 5277 持久化 |
SUIComponentUpdate 收到 303 面板且 yd_cy1=on |
| T04 | t04_get_hoe.lua |
已定案(2026-10-01 抓包,见协议定案文档附录A/B): CS1010 {"UserID":"10041","index":43}(等待图17:23 矿场总兵) → QFunction 面板 → CS1011 @func38_get_hzc;三态:入包帧(Index:50001)=成功→CS1003 穿锄;弹窗"5分钟后"(Btn1首充/Btn2 func_no)=等5min重试;弹窗"活动已结束"=skipped→T06 |
SC-1 入包帧含 Index:50001 |
| T05 | t05_mining.lua |
已定案(2026-10-01 抓包): 挖矿=客户端循环驱动(服务端无状态), CS3014 {"skillID":999,"dir":D,"destX/Y":面前障碍格,"srcX/Y":站位} @0.68s/锄(227帧实测);等待图矿=地图边界(0139.map 可走且邻障碍格, 离线可算);停止=不再发或走一步;产物走 SC-1 三形态(播报Type:5/金币ID:1累计/入包makeindex) |
配置时长到 或 "活动结束"播报;自身播报数>0 |
| T06 | t06_wait_zone.lua |
等待区 20min(服务端 114 倒计时/6098);结束后跟 6903 指引→传送 | SC51 且地图=新手村 |
| T07 | t07_kill_n.lua(参数化模板) |
5286 挂机+3014 战斗;SC55 任务进度;3031 领奖 | 参数:{地图=天然洞穴, n=10} 进度 10/10 且领奖(SC200) |
| T08 | 同 T07 | 参数:{比奇矿洞, 10} | 同上 |
| T09 | 同 T07 | 参数:{蜈蚣洞, 30} | 同上 |
| T10 | t10_shentong.lua |
直发 CS3199 {"index":39,"subid":1,"act":"@mingge_kaiqi,1"}(2026-09-30 真机抓包定案,见决策 D7;不走 6221 经络、不走 SSR 9001;@openmianban,1 仅为开 UI,headless 可省略) |
发出后 5s 内未收 SC100(Type=9)即成功;收到 SC100 含"等级不足"→告警(等级未达标) |
| T11 | t11_wuxing.lua |
任务指引路径(2026-09-30 tcpdump 二轮定案,推荐): CS3031 领[新手指引四]奖励 → CS1011 @renwu_qwyd,33(任务前往,服务端自动跨图传送盟重土城,免寻路) → 走到 NPC 10031(土城330:320) → CS1010 {"UserID":"10031","index":33} → 收五行面板(SC-1大帧,解开含"yd_wxjh,点击激活") → CS1011 {"UserID":"999999999","Act":"@func17_wxqh,1","index":999999999} 激活。备选手动路径: 已在土城时直接从第4步开始。原预案 3031领奖/SSR9001/873邮件 全部未走 |
激活后下一 SC-1 大帧含 [主线]新手指引五(任务链推进) 或道具入包推送(Index:50675 五行珠) 即成功 |
| T12 | t12_afk_woma.lua |
1010 土城传送员→1011 沃玛寺庙→634/51 到达→5286 开挂机 | SC20101 挂机态=开 且地图=沃玛 |
| T13 | t13_activity.lua |
开放式:监听 9001/3215/6511 等入口→按类型分发(答题 7511/战斗=战斗子模板/SSR) | 奖励到账(SC200/873) |
守护任务(并行):g_heartbeat.lua(10s,60000)、g_reconnect.lua(60004/60005/60006→重走登录链)、g_potion.lua(HP<阈值→1006 用药,SC53 监听;与 T03 的开关型喝药互补)。
配置示例(apilot_config.json,外置=决策 C):
{
"account": "longwu988", "zone": 14481607,
"tasks": ["T01","T02","T03","T04","T05@20m","T06","T07@天然洞穴,10","T08","T09","T10","T11","T12","T13@2h"],
"guards": ["heartbeat","reconnect","potion@hp<50"],
"role": {"job": 0, "sex": 0, "name_prefix": "萌新"}
}
| # | 决策 | 理由 |
|---|---|---|
| D1 | 运行时 = Lupa 源码构建 LuaJIT 2.1 | 与游戏引擎同款(LuaJIT 2.1.ROLLING 实证一致);lupa wheel 不带 macOS luajit(上游历史排除),已 patch setup.py + 预编 libluajit.a 验证可行;构建产物固化到 requirements/构建脚本 |
| D2 | 协议栈 = 复用已验证的 Python 实现(cq2_pure_enter/cq2_protocol_client 提炼) | 而非在 Lua 里重写 socket——Python 侧已在真实网关全链验证,风险最低;Lua 只做逻辑层 |
| D3 | 游戏原版 Lua 只读复用协议/Proxy 层,不复用 UI/状态机外壳 | 登录链由 APilot engine + stub 直驱 LoginProxy(它是纯协议 Proxy,无 UI 依赖);状态机外壳绑定 Director/Scene,不值得 stub |
| D4 | SSR 动态界面(任务 10/11/13)用 SubmitAct 直发 + 开发机客户端采集 schema | 已有实测样本(@chiyao_kaiqi/@startguaji);真客户端仅作开发期观察窗,生产目标机零客户端 |
| D5 | 文件通道保留(apilot_status.json/apilot_cmd.json) |
决策 2 的生产通道:宿主/外部系统可读状态、下指令;mobdebug 调试钩子列为可选工具,不在生产链路 |
| D6 | 任务只碰 AP.* API(铁律) |
架构自由度:未来换 adapter/复用到其他运行时零改动 |
| D7 | T10 神通开启 = SubmitAct @mingge_kaiqi,{slot} 直发(2026-09-30 真机双轮抓包定案) |
抓包文件已固化:protocol_bot/docs/cap_shentong_fail_20260930.jsonl(40级角色静默失败)+ cap_shentong_success_20260930.jsonl(35级槽成功+40级槽拒绝对照);原预案(6221 经络开穴/SSR 9001 双路径)全部未走。实证细节:①「神通」=服务端脚本 mingge(命格),客户端 Lua 零命中(仅敏感词表),纯服务端 SUI 系统;②打开面板=@openmianban,1(index=104,回 SC1109),点【神通】tab 无发包,headless 全部可省;③slot 参数:,1=35级槽,,2=40级槽(40级未到时回 SC100 Type=9 "等级不足:40");④开启成功无专属小回包,完成判定=5s 内无 SC100(Type=9);⑤服务端对 act 宽容错(真机曾发出截断的 @mingge_kaiq 仍回"等级不足"而非"命令无效");⑥每帧 SubmitAct 均伴随 CS6900(账号 token,开珍宝界面通知)——实现时按真实客户端节奏一并发送;⑦后续任务清单:T10b 40级 @mingge_kaiqi,2;⑧注意:神通开启后紧邻的 SC-1(recog=207) 大帧可能也携带 QFunction 面板(同 D8 机制,当时未解开),T10 实现时可复用 D8 解码器做正向确认,找不到再退回 SC100 负向判定 |
| D8 | T11 五行之力 = 任务指引+NPC QFunction 对话链(2026-09-30 真机抓包三轮定案);重大工具修正:①sniff_live(scapy版)对 zlib 压缩大帧 msgId 解析有 bug,SC 643(NPC对话)大帧被误标为 SC -1(recog=207,p1=299995);②scapy 用户态抓包在切图流量突发时丢包导致 SC 流脱同步——生产抓包一律改用内核级 tcpdump,离线重组解析 | 抓包文件已固化:protocol_bot/docs/cap_wuxing_npc_20260930.jsonl(scapy版,手动NPC路径)+ cap_wuxing_task4_tcpdump_20260930.pcap(tcpdump版,任务指引路径,零丢包)。链路细节:①NPC=盟重土城 330:320 的 NPC 10031(menuIndex=33);②任务指引路径更优:CS3031 领[指引四]奖励 → CS1011 @renwu_qwyd,33 服务端自动跨图传送(MapId=3 盟重土城),免跑图;③【激活五行之力】= CS1011 {"UserID":"999999999","Act":"@func17_wxqh,1","index":999999999}(999999999=QFunction 标准 UserID);④面板/回执帧 = SC-1(recog=207) 大帧,body=zlib→decode6 双层编码,解开为 QFunction SUI 富文本(未激活态含"yd_wxjh,点击激活");⑤成功信号双保险:任务链推进帧([主线]新手指引五)或五行珠入包(Index:50675,where=12);⑥T10 神通(@mingge_kaiqi)与 T11 五行(@func17_wxqh)同属 QFunction 脚本家族,实现共用"1010→1011→-1大帧解码"器;⑦原预案 3031领奖→SSR9001→873邮件→3078/3081 全部未走 |
| D9 | T04/T05 挖矿链定案(2026-10-01 五轮真机演示);核心认知:挖矿=客户端心跳循环,服务端无会话状态;领锄头三态窗口(0-5/5-20/20+min)各有精确帧信号;等待图矿=地图边界(0139.map 离线可算) | 详见 protocol_bot/docs/协议定案-神通开启与五行之力.md 附录A/B + 会话总结-20261001-挖矿链定案与五轮演示.md;证据 pcap×4 已固化。要点:①领取=1010{10041,43}→@func38_get_hzc,成功=入包 Index:50001,然后 CS1003 空body 穿锄(易漏);②"5分钟后"弹窗带 Btn1(@openmianban,26 首充)/Btn2(@func_no),机器人点 Btn2 等待,不点首充;③挖矿帧 {"skillID":999,"dir":D,"destX/Y":障碍格,"srcX/Y":站位} 无 targetID,0.68s/锄照抄;④产物无 610 帧,走 SC-1 播报(Type:5)/金币累计/入包;⑤首跑脚本 protocol_bot_backup/run_mine998.py(combat_bot 已加 raw_frame_hook 旁路);⑥账号 longwu998 密码错误勿用,用 longwu988/Longwu1988 |
| 风险 | 等级 | 对策 |
|---|---|---|
| 绑定面清单有缺项,游戏 Lua 加载即 nil 崩 | 高频但低危 | 万能 no-op 工厂兜底 + 逐项覆盖;每崩一次补一个,收敛可预期(登录链 API 面有界) |
| SSR schema 未知(任务 13) | 中 | 开发机装客户端抓包采集;任务模块留双路径分支;首版可先跳过 T13 交付(T10/T11 已于 2026-09-30 抓包定案,风险解除) |
| 服务端风控识别非真实客户端行为模式(帧节奏/初始化序列) | 中 | 17 帧初始化序列已实测照发;tick 节奏对齐真实引擎(50ms);低频操作加随机抖动 |
| sdata/Encode6BitBuf 细节不一致 | 低 | 已在 Python 全链验证(与真实客户端字节一致) |
| LuaJIT 构建在各目标机不可复现 | 低 | 预编 libluajit.a + 打补丁的 lupa 以内部 wheel/子模块固化;Linux CI 出 wheel |
| 游戏版本更新导致协议变化 | 低(近期稳定) | netMessageDef 与服务端强相关;更新时重新解密对齐(加密器已字节级验证) |
| 阶段 | 内容 | 通过标准 |
|---|---|---|
| V1 stub 骨架 | 万能 no-op + 网络类真实实现;Lua 加载 netMessageDef/framework/networkUtil/LoginProxy 无错 | 加载零报错;AP.send 能出真实字节(与 Python 直发比对一致) |
| V2 登录链 | T01 创角全流程(逐鹿05区) | 收 521;角色出现在 520 列表;lsof/netstat 确认 TCP 会话 |
| V3 世界与喝药 | T02+T03+守护心跳 60s | SUI 303 面板 yd_cy1=on;60000 心跳间隔 10s±;会话存活 |
| V4 作业任务 | T04/T05(领锄头+挖矿 20min) | SC200 锄头;挖矿产物播报计数>0 |
| V5 全流程 | T01→T13 连跑(含参数化杀怪) | 每任务完成判定为真;全程无人工干预 |
| V6 部署验证 | 干净 Mac(无任何游戏文件)+ Linux CI | git clone + pip install + 一条命令跑通 V2-V3 |
传奇/
├── apilot/ # Python 宿主+stub+协议栈(新)
│ ├── host.py bridge.py wire.py http_login.py config.py main.py
│ └── stubs/ (net_client.py network_ctl.py scheduler.py env.py noop.py)
├── apilot_lua/ # APilot 框架 Lua(新)
│ ├── init.lua bus.lua engine.lua api.lua guard_*.lua
│ └── tasks/ (t01..t13)
├── lua_src/ # 游戏原版解密 Lua(只读镜像,git 管理;来源 lua脚本解密源码/)
├── protocol_bot/ # 既有验证资产(login_996pc/cq2_pure_enter 等,提炼复用)
├── docs/superpowers/specs/ # 本文档
└── tools/ # lupa-luajit 构建脚本(wheel 固化)