Files

5.9 KiB
Vendored
Raw Permalink Blame History

AnantaInjector(注入器最小依赖副本)

从 C:\Game\Ananta_mainleakflow_keitaro_gg\AnantaUnifiedLoader 里只挑出需要的部分拷过来的, 给服务端根目录那个 一键启动.exe 用。

带的模块

模块 通道 作用
modules/bowling_agent.js C 保龄球球瓶
modules/balloon_fix.js C 打气球的气球本体

故意不放的那些(服务端已经接管,注入器再开就是白刷负载):

  • gadget_loader(A 户外 gadget 网格)→ 服务端 GameRouter.GadgetGrid.cs
  • world_mod(B 场景物品网格)→ 服务端 GameRouter.SceneItemGrid.cs
  • train(D 地铁座位 / E 室内扇区)→ 服务端 GameRouter.MetroGadget.cs / indoorSectors
  • addbtn(F 提示按钮)→ 客户端自己会出 F,已降级为手动兜底
  • settingsfix(设置-图像页错位行)→ 纯手动 RPC,无常驻行为

✅ balloon 现在是可用的(2026-09-29 修):GameRouter.Balloon.cs 已就位,服务端每次 push 会写 %LOCALAPPDATA%\AnantaBalloon\balloon_push.json(实测 21:07 写过 16 条)。 ⛑ 但 balloon_fix.js:3417 的 PUSH_PATHS 默认是作者自己机器的 D:\Ananta\gym_tools\_balloon_push.json, R146 注释写明「exe 加载器会把这一行整个改写成本机多路径」。原版 exe 做了,我们之前没做 ⇒ agent 读不到 ⇒ pushN 恒 0 ⇒ 一颗气球都不出。 现在由 loader_common.apply_balloon_paths() 在 create_script 前改写(js 文件本身仍与上游逐字节一致)。

分组开关(2026-10-01)

每个模块用 "group": "xxx" 声明组别,config.json 顶层 groups 整组一起开关, 改完重启加载器生效(config 只在启动时读一次):

"groups": { "minigame": true }
  • 目前只有一组:minigame(= bowling + balloon)。
  • ⛔ traffic 组(modules/vehicle_go.js)已于 2026-10-01 晚整组删除,不要再加回来: 它 hook 的 AetherVehicleViewManager:CheckShouldNotUseGo(RVA 0x0B108F00)实机 8 探针 全 0 命中 ⇒ 那个类根本没在用。车流现改走服务端 trafficCruiseDrive (SyncAssignVehicleAITask 68549522 + VehicleCruiseParameters,客户端本地 AI 开车)。
  • ⛑ 与模块自身的 enabled、命令行 --no a,b 是叠加关系 —— 任一处关掉就不挂。
  • ⛑⛑ 别复制第二份目录去"跑两个加载器":同一时刻只能有一个 frida 会话挂在 Ananta.exe 上 (两个 = 游戏必崩),常驻模式靠 .loader.lock 挡着。所谓"拆分"是同一进程内的模块取舍。

两道保险(针对「注入器是不是得先进入世界再启动」)

① 进入世界闸门 attachGate

bowling_agent.js:5547 / balloon_fix.js 里装 hook 的 Il2Cpp.perform(...) 没有重试:

var blob = bfClass('LX6.Item.SceneItemBlob');
if (!blob) { sendlog('ERR: SceneItemBlob not found'); return; }   // ← 永久放弃

所以「游戏刚起就挂」是有真实风险的。闸门的做法:先看服务端日志里有没有 只有 world-ready 之后才会打的行,命中了再 attach —— 等价于复现手动操作时 「进世界 → 再开加载器」这条已经验证过的顺序。

标记(任意一条命中即放行):

  • [RESTOCK] raid=
  • [GADGET-GRID] push group
  • [SCENE-ITEM-GRID] push group

⛑ 只扫本次开始跟踪之后新增的字节,不会把上一局的历史内容当成「已进世界」。 ⛑ 三条 marker 对应的服务端功能全关掉时,闸门会走 timeoutSec(默认 900s)超时兜底, 按 fallback=attachAnyway 照样挂 —— 不会把你卡死。

想关掉闸门(排查时用):config.json 里 attachGate.mode 改成 process。

② armed 守卫 armedGuard

闸门只保证「时机对」,不保证脚本里那次 bfClass(...) 真的成功。 所以 attach 之后持续轮询 bfStatus.armed:

  • armed=true → 正常。tpl=false 是正常的(还没拿到模板),不会因此重挂
  • armed=false → 说明脚本里 return 掉了 ⇒ 等 maxWaitSec(60s)后主动重挂

最多连试 maxAttempts(5)次,之后退避 backoffSec(120s)再试,不会无限刷。

手动跑

C:\Users\Noiro\.workbuddy\binaries\python\envs\default\Scripts\python.exe unified_loader.py

其它命令同 AnantaUnifiedLoader:diag / scan / rpc <模块> <RPC> [参数] / --no a,b。

⛑ 同一时刻只能有一个 frida 会话挂在 Ananta.exe 上(两个 = 游戏必崩)。 常驻模式用 .loader.lock 挡着;手动 rpc 之前请先关掉常驻窗口。

injector_status.json(界面靠它显示状态)

注入器会把自己的状态写进同目录 injector_status.json,根目录那个「一键启动」界面每秒读一次, 所以界面上的「已启动 / 等待 / 已注入」是真实状态,不是瞎猜的:

state 界面显示
starting 正在启动…
waiting_game 已启动,等待游戏打开
waiting_world 已启动,等你进入游戏世界
attached 已连上客户端,正在装载…
injected 已注入(保龄球瓶 + 气球生效)
stopped 已退出

界面还会用文件里的 pid 判断注入器进程是否还活着(不是看「有没有 python 进程」, 那样会被机器上别的 python 误导)。

判活

... unified_loader.py rpc bowling bfStatus
... unified_loader.py rpc balloon bfStatus
  • bowling:armed=true 且 tpl=true 才真的生效。tpl=false 就站进保龄球馆让 AOI 表加载一次 (模板是「等客户端自己成功查一次表」时顺手收的)。
  • balloon:armed=true 即可;pushN 是服务端推送条目数 —— 必须 >0, pushErr 会写清是哪几个候选路径读不到(修好后应为 none、pushSrc 指向 LOCALAPPDATA 那份)。