# iScout para Evony (lectura de memoria via Frida)

Lee TODOS los monstruos/bosses del mapa directamente de la memoria del juego:
coordenadas exactas, nivel, tipo, id. Instantáneo, sin escaneo visual, sin
drift, sin falsos positivos. Es el método que usa "iScout".

Esto es el **Camino B/memoria**: máximo riesgo de baneo (es justo lo que el
anti-cheat de Evony busca). Cuenta desechable, sesiones cortas. Bajo tu riesgo.

## Cómo funciona

- Emulador Android **rooteado** (Android Studio AVD, imagen `google_apis` arm64).
  BlueStacks Air NO sirve (no da root).
- `frida-server` corre dentro del emulador como root.
- `agent.js` (compilado de `agent.ts` con frida-il2cpp-bridge):
  - Hookea `ServerMapLayer.GetNewMapObject/AddPosition/RefreshPvpMonster`
    con `Interceptor.attach` + **lecturas crudas de memoria** (no API il2cpp
    dentro del callback → no crashea).
  - Vuelca la config `id -> {nombre, nivel, tipo}` (1880 monstruos) via
    `ConfigureManager.GetMonsterConfigOfAll()`.
  - Acumula y deduplica por `(wx,wy)`, envía lotes cada 3s (batching →
    no inunda el canal RPC, que era lo que mataba al cliente).
- `iscout.py` recibe los lotes, anota con la config y escribe `scout_bosses.csv`.

## Estructura clave descubierta (reversing IL2CPP, Unity 2022.3.62f2)

- `evony-proto-up.dll :: Msg.mapinfo` — cada objeto del mapa.
  Offsets: `__type@16  __wx@24  __wy@28  __id@32  __level@36`
- `Assembly-CSharp.dll :: ServerMapLayer` — capa del mapa del mundo.
  Campo `mapObjectMap : Dictionary<int,MapObject>` = todos los objetos vivos.
- `NetworkManager.DecodeCallback(MsgDown.down_msg,...)` — dispatch de red
  (no usado al final; el hook por objeto es más fiable).
- `MsgDown.request_worldmap_reply.__mapinfo` — lista que envía el servidor
  por región al panear.

## Requisitos (reproducir desde cero)

```bash
brew install --cask android-commandlinetools
brew install openjdk@17
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
export ANDROID_SDK_ROOT=/opt/homebrew/share/android-commandlinetools
yes | sdkmanager --licenses
sdkmanager "platform-tools" "emulator" "platforms;android-34" \
           "system-images;android-34;google_apis;arm64-v8a"
echo no | avdmanager create avd -n evony_root \
           -k "system-images;android-34;google_apis;arm64-v8a" -d pixel_6 --force
# arrancar
$ANDROID_SDK_ROOT/emulator/emulator -avd evony_root -no-snapshot \
   -writable-system -gpu auto -memory 4096 -partition-size 8192 -no-audio &
adb wait-for-device && adb -e root
# instalar Evony (APKs extraidos de otro dispositivo con: adb pull de /data/app/...)
adb -s emulator-5554 install-multiple base.apk split_config.arm64_v8a.apk split_install_time_asset_pack.apk
# frida
pip3 install frida-tools          # version debe casar con frida-server
adb -s emulator-5554 push frida-server-17.9.10-android-arm64 /data/local/tmp/frida-server
adb -s emulator-5554 shell chmod 755 /data/local/tmp/frida-server
adb -s emulator-5554 shell "nohup /data/local/tmp/frida-server >/dev/null 2>&1 &"
```

Recompilar el agente (si tocas `agent.ts`):
```bash
cd <dir con node_modules de frida-il2cpp-bridge + frida-compile>
node_modules/.bin/frida-compile agent.ts -o agent.js   # node 18+ (no v12)
```

## Interfaz web (recomendado)

```bash
cd /Users/danicosta/Desktop/Evony/iscout
/Applications/Xcode.app/Contents/Developer/usr/bin/python3 iscout_web.py
# abre http://127.0.0.1:8770
```

Backend Frida + barrido automático + servidor web. La página:
- Multi-select de bosses (se rellena con lo encontrado, con conteo)
- Filtro por tipo (Monstruos rally / castillos / jugadores)
- Centro X/Y + radio (tiles) o todo el mapa
- Orden por nivel / poder / distancia / reciente
- Tabla en vivo (auto-refresh 4s) con poder formateado y botón copiar `x,y`

API: `GET /api/data?bosses=A||B&type=2&cx=&cy=&radius=&sort=&limit=`,
`GET /api/names`.

## Uso CLI (solo CSV, sin web)

### BARRIDO AUTOMÁTICO — no tocas nada

`agent.js` = barrido automático. Teletransporta la cámara por una rejilla de
todo el mapa con `WorldMapManager.jumpToServer` y captura cada región. NO hay
que panear a mano.

1. Emulador arrancado y rooteado, `frida-server` corriendo, Evony abierto en
   el mapa del reino.
2. Lanza:
   ```bash
   cd /Users/danicosta/Desktop/Evony/iscout
   /Applications/Xcode.app/Contents/Developer/usr/bin/python3 iscout.py
   ```
3. **Déjalo correr solo.** Recorre el mapa entero (~1024 puntos, rejilla
   serpiente). En 35s ya captura ~3000 objetos; el barrido completo tarda
   ~20-24 min pero el CSV se actualiza en vivo desde el primer segundo.
4. Ctrl+C para parar cuando quieras. CSV: `name,level,type,x,y,id` ordenado
   por nivel desc, deduplicado por coordenada.

Ajustes del barrido en `agent_sweep.ts` (recompilar tras tocar):
- `X_MIN/X_MAX/Y_MIN/Y_MAX` — región a barrer (default todo: 50..1000)
- `STEP` — tiles entre jumps (30; menor = más solape, más lento)
- `JUMP_INTERVAL_MS` — ms entre jumps (1400; menor = más rápido, menos fiable)

Modo manual antiguo: `agent_sweep.*` es el auto; si quisieras solo capturar
lo que paneas a mano, usa una versión sin el hook de `Update`.

`type=2` = monstruos de mapa (los que rallyeas). `type=3` = otra categoría.
`type=1/5/7` = castillos de jugador / NPC.

## Nombres (resuelto)

Nombres en inglés vía `LocalizationManager.GetString2(key)`. Clave: usar
`Il2Cpp.String.content` (no `.toString()`, que mete comillas literales y
rompe el lookup). Salida tipo `(Boss) Minotaur`, `Hypocritical Knight`,
`Sphinx`. Si quieres otro idioma, depende del idioma de la cuenta Evony.

## Automatizar barrido completo (pendiente, opcional)

`WorldMapManager.JumpToGrid(x,y,...)` permite teletransportar la cámara por
código. Un bucle que salte por una rejilla de la región + lea el cache daría
el server entero sin paneo manual. La parte difícil (root, RE, extracción
estable) ya está resuelta; esto es solo orquestación.
