122 lines
5.9 KiB
Markdown
122 lines
5.9 KiB
Markdown
# 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 只在启动时读一次):
|
||
|
||
```json
|
||
"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(...)` **没有重试**:
|
||
|
||
```js
|
||
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 那份)。
|