@ing.jorgeu/wargaming-overlay 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/PUBLISHING.md +35 -0
- package/README.md +471 -0
- package/THIRD_PARTY_ASSETS.md +7 -0
- package/battle_reader.py +110 -0
- package/cli.js +78 -0
- package/diagnostics.js +38 -0
- package/game-store.js +17 -0
- package/package.json +46 -0
- package/platform.js +46 -0
- package/public/assets/deathwatch-texture.png +0 -0
- package/public/assets/faction-emblem-placeholder.png +0 -0
- package/public/assets/factions/adepta-sororitas.png +0 -0
- package/public/assets/factions/adeptus-custodes.png +0 -0
- package/public/assets/factions/adeptus-mechanicus.png +0 -0
- package/public/assets/factions/aeldari.png +0 -0
- package/public/assets/factions/agents-of-the-imperium.png +0 -0
- package/public/assets/factions/astra-militarum.png +0 -0
- package/public/assets/factions/black-templars.png +0 -0
- package/public/assets/factions/blood-angels.png +0 -0
- package/public/assets/factions/chaos-daemons.png +0 -0
- package/public/assets/factions/chaos-knights.png +0 -0
- package/public/assets/factions/chaos-space-marines.png +0 -0
- package/public/assets/factions/custom.png +0 -0
- package/public/assets/factions/dark-angels.png +0 -0
- package/public/assets/factions/death-guard.png +0 -0
- package/public/assets/factions/deathwatch.png +0 -0
- package/public/assets/factions/drukhari.png +0 -0
- package/public/assets/factions/emperors-children.png +0 -0
- package/public/assets/factions/genestealer-cults.png +0 -0
- package/public/assets/factions/grey-knights.png +0 -0
- package/public/assets/factions/imperial-knights.png +0 -0
- package/public/assets/factions/leagues-of-votann.png +0 -0
- package/public/assets/factions/necrons.png +0 -0
- package/public/assets/factions/orks.png +0 -0
- package/public/assets/factions/space-marines.png +0 -0
- package/public/assets/factions/space-wolves.png +0 -0
- package/public/assets/factions/tau-empire.png +0 -0
- package/public/assets/factions/thousand-sons.png +0 -0
- package/public/assets/factions/tyranids.png +0 -0
- package/public/assets/factions/world-eaters.png +0 -0
- package/public/assets/formations/disruption.png +0 -0
- package/public/assets/formations/priority-assets.png +0 -0
- package/public/assets/formations/purge-the-foe.png +0 -0
- package/public/assets/formations/reconnaissance.png +0 -0
- package/public/assets/formations/take-and-hold.png +0 -0
- package/public/assets/generic-texture.png +0 -0
- package/public/assets/thousand-sons-texture.png +0 -0
- package/public/battle-title.css +2 -0
- package/public/control.html +3 -0
- package/public/control.js +35 -0
- package/public/detachments.css +5 -0
- package/public/faction-medallion.css +6 -0
- package/public/formations.css +5 -0
- package/public/generic-texture.css +1 -0
- package/public/live-score.css +7 -0
- package/public/live-score.js +49 -0
- package/public/overlay-art.html +1 -0
- package/public/overlay-v4-pre-art.css +10 -0
- package/public/overlay-v4.css +10 -0
- package/public/overlay-wide.html +1 -0
- package/public/overlay.html +1 -0
- package/public/overlay.js +13 -0
- package/public/resolution.css +2 -0
- package/public/resolution.js +9 -0
- package/public/style.css +1 -0
- package/reader.py +36 -0
- package/server.js +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Zero-Clause BSD
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for
|
|
5
|
+
any purpose with or without fee is hereby granted.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
8
|
+
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
9
|
+
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
|
10
|
+
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
|
11
|
+
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
|
12
|
+
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
13
|
+
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/PUBLISHING.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Preparación para npm
|
|
2
|
+
|
|
3
|
+
La versión 2.1.0 está empaquetada para distribución, pero NO se ha publicado ni instalado globalmente en el equipo del usuario.
|
|
4
|
+
|
|
5
|
+
## Pendiente de decidir
|
|
6
|
+
|
|
7
|
+
- Nombre elegido: `@ing.jorgeu/wargaming-overlay`. Publicar con la cuenta npm `ing.jorgeu`, confirmada por el titular.
|
|
8
|
+
- Licencia del código resuelta: **0BSD**, seleccionada por el usuario. Permite uso comercial, modificación y redistribución sin atribución obligatoria. Las imágenes requieren revisión por separado.
|
|
9
|
+
- Revisar la procedencia y permiso de redistribución de los recursos visuales; ver `THIRD_PARTY_ASSETS.md`.
|
|
10
|
+
- Añadir `repository`, `homepage`, `bugs` y `author` cuando se conozcan. No se han inventado datos personales ni URLs.
|
|
11
|
+
- Ejecutar el workflow de GitHub Actions en las tres plataformas y probar USB real en Windows y Linux. Aquí solo se validó macOS físicamente; las ramas de otras plataformas se prueban con escenarios simulados.
|
|
12
|
+
|
|
13
|
+
## Primera publicación manual
|
|
14
|
+
|
|
15
|
+
Desde la raíz del proyecto, ya con las decisiones anteriores resueltas:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm test
|
|
19
|
+
npm pack --dry-run
|
|
20
|
+
npm login
|
|
21
|
+
npm whoami
|
|
22
|
+
npm view @ing.jorgeu/wargaming-overlay name version
|
|
23
|
+
npm publish --dry-run
|
|
24
|
+
npm publish --access public
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Si el nombre existe y no eres su propietario, cambia `name` a `@tu-scope/wargaming-overlay` (sustituyendo el ejemplo por un scope real). Consulta el nombre elegido con `npm view` antes de publicar. Un 404 puede significar que el nombre no existe; otros errores no prueban disponibilidad. Usa una versión nueva si ya fue publicada.
|
|
28
|
+
|
|
29
|
+
El último comando publica realmente. No se ha ejecutado. La autenticación y la verificación de npm deben completarse en tu sesión; no guardes tokens en el repositorio.
|
|
30
|
+
|
|
31
|
+
`prepublishOnly` ejecuta las pruebas. `files` limita el paquete a código, interfaz y documentación; no incluye estado personal, backups, pruebas ni workflows. No hay scripts de instalación automáticos. ADB se instala únicamente al invocar `setup --install-adb`.
|
|
32
|
+
|
|
33
|
+
Para releases posteriores se puede configurar Trusted Publishing con GitHub Actions desde la configuración del paquete en npm. No se ha creado un workflow de publicación con repositorio o identidad inventados.
|
|
34
|
+
|
|
35
|
+
Fuentes oficiales: [npm publish](https://docs.npmjs.com/cli/v7/commands/npm-publish/), [Trusted Publishing](https://docs.npmjs.com/trusted-publishers/).
|
package/README.md
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# Wargaming Overlay
|
|
2
|
+
|
|
3
|
+
Overlay local para OBS con marcador, ronda, CP, primarias y secundarias leídos de un teléfono Android. Incluye panel de configuración, vínculo de jugadores por nombre, indicadores de misión cumplida, persistencia de la partida y botón para restablecer los datos.
|
|
4
|
+
|
|
5
|
+
**Paquete:** `@ing.jorgeu/wargaming-overlay` · **Comando:** `wargaming-overlay` · **Licencia del código:** 0BSD.
|
|
6
|
+
|
|
7
|
+
El paquete está preparado para npm, pero no se ha publicado desde este proyecto. `@ing.jorgeu` debe corresponder a la cuenta u organización real que publique. Hasta entonces, instala desde el código fuente o un archivo `.tgz`.
|
|
8
|
+
|
|
9
|
+
## Contenido
|
|
10
|
+
|
|
11
|
+
- [Requisitos](#requisitos)
|
|
12
|
+
- [Instalar dependencias en macOS](#macos)
|
|
13
|
+
- [Instalar dependencias en Windows](#windows)
|
|
14
|
+
- [Instalar dependencias en Linux](#linux)
|
|
15
|
+
- [Instalar el CLI](#instalar-el-cli)
|
|
16
|
+
- [Preparar el teléfono](#preparar-el-teléfono)
|
|
17
|
+
- [Primer inicio y configuración de OBS](#primer-inicio-y-configuración-de-obs)
|
|
18
|
+
- [Comandos y ejemplos](#comandos-y-ejemplos)
|
|
19
|
+
- [Migrar, guardar y restablecer](#migrar-guardar-y-restablecer)
|
|
20
|
+
- [Solución de problemas](#solución-de-problemas)
|
|
21
|
+
- [Actualizar y desinstalar](#actualizar-y-desinstalar)
|
|
22
|
+
- [Desarrollo y publicación](#desarrollo-y-publicación)
|
|
23
|
+
|
|
24
|
+
## Requisitos
|
|
25
|
+
|
|
26
|
+
| Dependencia | Requisito y función | Descarga oficial |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Node.js y npm | Node 20 o posterior; preferir una versión LTS mantenida. Ejecuta el CLI y servidor. npm viene con las instalaciones habituales de Node. | [Node.js](https://nodejs.org/en/download/) |
|
|
29
|
+
| Python | Python 3.8 o posterior; preferir una versión mantenida. Interpreta el XML de Android. | [Python](https://www.python.org/downloads/) |
|
|
30
|
+
| ADB | Android SDK Platform-Tools. Comunica el equipo con el teléfono. | [Platform-Tools](https://developer.android.com/tools/releases/platform-tools) |
|
|
31
|
+
| OBS Studio | Fuente Navegador disponible. Muestra el overlay sobre el vídeo. | [OBS Studio](https://obsproject.com/download) |
|
|
32
|
+
| Teléfono Android | App Tabletop Battles abierta en la ronda, opciones de desarrollador y depuración USB habilitadas. | [Conectar un dispositivo Android](https://developer.android.com/studio/run/device) |
|
|
33
|
+
| Cable USB | Debe transmitir datos, no solo cargar. | — |
|
|
34
|
+
|
|
35
|
+
No requiere Android Studio completo, Java, paquetes pip, OCR ni dependencias npm adicionales. No lee iPhone/iOS. Aunque el nombre del proyecto es genérico, el parser actual está adaptado a la interfaz Android de Tabletop Battles; no interpreta automáticamente otras aplicaciones.
|
|
36
|
+
|
|
37
|
+
El servidor escucha únicamente en `127.0.0.1`, puerto **8765** por defecto. No necesita `sudo` ni ejecutarse como administrador. La instalación de dependencias del sistema sí puede solicitar permisos. Se necesita internet para descargar software; la lectura y el overlay funcionan localmente.
|
|
38
|
+
|
|
39
|
+
**Validación:** macOS probado con un Galaxy real. Windows y Linux tienen soporte de rutas/instaladores y escenarios simulados en las pruebas. La matriz de CI está preparada para las tres plataformas; las pruebas físicas de USB en Windows/Linux siguen pendientes. No se ha medido todavía el impacto durante una transmisión real 1440p60.
|
|
40
|
+
|
|
41
|
+
## macOS
|
|
42
|
+
|
|
43
|
+
1. Instala [Homebrew](https://brew.sh/) siguiendo las instrucciones de su página, si quieres usarlo. Abre una nueva Terminal después de instalarlo.
|
|
44
|
+
2. Instala las dependencias:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
brew install node python
|
|
48
|
+
brew install --cask android-platform-tools
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. Comprueba las versiones:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
node --version
|
|
55
|
+
npm --version
|
|
56
|
+
python3 --version
|
|
57
|
+
adb version
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
4. Instala OBS desde su [página oficial](https://obsproject.com/download).
|
|
61
|
+
5. Continúa con [Instalar el CLI](#instalar-el-cli).
|
|
62
|
+
|
|
63
|
+
Sin Homebrew, instala Node y Python desde sus páginas oficiales y descarga el ZIP de Platform-Tools para Mac. Extrae el ZIP, por ejemplo en `$HOME/Android/platform-tools`. Puedes añadir esa carpeta al PATH de esta sesión:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
export PATH="$HOME/Android/platform-tools:$PATH"
|
|
67
|
+
adb version
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Para conservarlo, añade esa línea a `~/.zshrc` y abre otra Terminal. También puedes usar `--adb "$HOME/Android/platform-tools/adb"` sin modificar PATH. macOS no necesita drivers USB adicionales para ADB. [Referencia de Homebrew para ADB](https://formulae.brew.sh/cask/android-platform-tools).
|
|
71
|
+
|
|
72
|
+
## Windows
|
|
73
|
+
|
|
74
|
+
Los ejemplos usan **PowerShell**. Ejecuta el overlay como usuario normal.
|
|
75
|
+
|
|
76
|
+
1. Instala Node.js LTS desde [Node.js](https://nodejs.org/en/download/). Incluye npm.
|
|
77
|
+
2. Instala Python desde [Python para Windows](https://www.python.org/downloads/windows/), siguiendo la [guía oficial](https://docs.python.org/3/using/windows.html). Abre otra terminal al finalizar.
|
|
78
|
+
3. Instala ADB con WinGet:
|
|
79
|
+
|
|
80
|
+
```powershell
|
|
81
|
+
winget install --exact --id Google.PlatformTools --source winget
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Si no tienes WinGet, consulta [su instalación oficial](https://learn.microsoft.com/en-us/windows/package-manager/winget/), o descarga Platform-Tools para Windows desde [Google](https://developer.android.com/tools/releases/platform-tools). Extrae el ZIP, por ejemplo en `C:\Android\platform-tools`.
|
|
85
|
+
|
|
86
|
+
4. Abre una nueva PowerShell y comprueba:
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
node --version
|
|
90
|
+
npm.cmd --version
|
|
91
|
+
python --version
|
|
92
|
+
adb version
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Si Python está instalado mediante el launcher y `python` no responde, prueba `py -3 --version`. El CLI busca `python3`, `python` y el launcher `py`.
|
|
96
|
+
|
|
97
|
+
5. Si el teléfono no aparece, instala el [driver USB de su fabricante](https://developer.android.com/studio/run/oem-usb). Para Samsung, consulta el [driver oficial](https://developer.samsung.com/android-usb-driver).
|
|
98
|
+
6. Instala [OBS](https://obsproject.com/download) y continúa con [Instalar el CLI](#instalar-el-cli).
|
|
99
|
+
|
|
100
|
+
Si extrajiste ADB manualmente, puedes usar una ruta explícita:
|
|
101
|
+
|
|
102
|
+
```powershell
|
|
103
|
+
wargaming-overlay.cmd doctor --adb "C:\Android\platform-tools\adb.exe"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
O añadirla al PATH de la sesión:
|
|
107
|
+
|
|
108
|
+
```powershell
|
|
109
|
+
$env:Path = "C:\Android\platform-tools;" + $env:Path
|
|
110
|
+
adb version
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Para hacer el cambio permanente, añade la carpeta a la variable **Path de tu usuario** desde las variables de entorno de Windows y abre otra terminal. Si PowerShell bloquea `npm.ps1`, usa `npm.cmd`; para el CLI usa `wargaming-overlay.cmd`. No hace falta cambiar la política de ejecución. [Referencia del instalador WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/install).
|
|
114
|
+
|
|
115
|
+
## Linux
|
|
116
|
+
|
|
117
|
+
Instala las dependencias con el gestor de tu distribución. Comprueba siempre que `node --version` sea 20 o superior; si tu repositorio ofrece una versión más antigua, sigue una opción adecuada de la [guía oficial de Node.js](https://nodejs.org/en/download/).
|
|
118
|
+
|
|
119
|
+
### Debian / Ubuntu
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
sudo apt-get update
|
|
123
|
+
sudo apt-get install nodejs npm python3 adb android-sdk-platform-tools-common
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Si ADB informa que faltan permisos USB, comprueba el grupo `plugdev`:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
id -nG
|
|
130
|
+
sudo usermod -aG plugdev "$USER"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
El segundo comando es necesario solo si tu usuario no pertenece al grupo. Cierra sesión y vuelve a entrar para aplicar el cambio. Las reglas udev se incluyen en `android-sdk-platform-tools-common`. [Guía Android para Ubuntu](https://developer.android.com/studio/run/device), [paquete adb](https://packages.ubuntu.com/en/jammy/adb).
|
|
134
|
+
|
|
135
|
+
### Fedora
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
sudo dnf install nodejs npm python3 android-tools
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Si hay errores de permisos, revisa las reglas udev y permisos USB de tu distribución. No asumas que existe el grupo `plugdev` ni ejecutes el overlay con sudo. [Paquete android-tools de Fedora](https://packages.fedoraproject.org/pkgs/android-tools/android-tools/).
|
|
142
|
+
|
|
143
|
+
### Arch Linux
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
sudo pacman -Syu nodejs npm python android-tools android-udev
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Este comando actualiza el sistema además de instalar las dependencias; revisa la operación que presenta pacman. [Paquete android-tools de Arch](https://archlinux.org/packages/extra/x86_64/android-tools/).
|
|
150
|
+
|
|
151
|
+
### Otras distribuciones y comprobación
|
|
152
|
+
|
|
153
|
+
Instala Python 3 y ADB con tu gestor o usa [Platform-Tools oficiales](https://developer.android.com/tools/releases/platform-tools). `setup` no instala automáticamente en distribuciones sin apt-get, dnf o pacman.
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
node --version
|
|
157
|
+
npm --version
|
|
158
|
+
python3 --version
|
|
159
|
+
adb version
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Instala OBS siguiendo las [instrucciones oficiales para Linux](https://obsproject.com/kb/linux-installation) y comprueba que incluya la fuente Navegador.
|
|
163
|
+
|
|
164
|
+
## Instalar el CLI
|
|
165
|
+
|
|
166
|
+
Elige **una** opción. La instalación del paquete no instala ADB o Python automáticamente.
|
|
167
|
+
|
|
168
|
+
### A. Desde el código fuente, disponible ahora
|
|
169
|
+
|
|
170
|
+
Descarga/descomprime el proyecto, o clónalo si tienes la URL del repositorio. Abre una terminal en la carpeta que contiene `package.json`:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
npm install -g .
|
|
174
|
+
wargaming-overlay --version
|
|
175
|
+
wargaming-overlay --help
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
En PowerShell puedes usar `npm.cmd install -g .` y `wargaming-overlay.cmd --help`.
|
|
179
|
+
|
|
180
|
+
También puedes usarlo **sin instalar globalmente**, desde esa carpeta:
|
|
181
|
+
|
|
182
|
+
```sh
|
|
183
|
+
node cli.js doctor
|
|
184
|
+
npm start
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### B. Desde un archivo de paquete
|
|
188
|
+
|
|
189
|
+
Sustituye la ruta por la del archivo que recibiste:
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
npm install -g "/ruta/ing.jorgeu-wargaming-overlay-2.2.0.tgz"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Ejemplo Windows:
|
|
196
|
+
|
|
197
|
+
```powershell
|
|
198
|
+
npm.cmd install -g "$HOME\Downloads\ing.jorgeu-wargaming-overlay-2.2.0.tgz"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### C. Desde npm, después de publicarlo
|
|
202
|
+
|
|
203
|
+
```sh
|
|
204
|
+
npm install -g @ing.jorgeu/wargaming-overlay
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Ese comando requiere que el paquete ya exista en npm. Si el scope definitivo cambia, usa el nombre publicado. Un error 404 antes de publicar no significa que tu instalación de Node esté mal.
|
|
208
|
+
|
|
209
|
+
### Evitar EACCES en macOS / Linux
|
|
210
|
+
|
|
211
|
+
Puedes instalar en una carpeta de tu usuario, sin sudo:
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
npm install -g --prefix "$HOME/.local" .
|
|
215
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
216
|
+
wargaming-overlay --version
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Para conservar el PATH, añade la línea `export PATH` a `~/.zshrc` si usas zsh, o `~/.bashrc` si usas bash. Abre otra terminal. En esta modalidad, usa el mismo `--prefix "$HOME/.local"` al reinstalar o desinstalar. [Documentación npm install](https://docs.npmjs.com/cli/v8/commands/npm-install/).
|
|
220
|
+
|
|
221
|
+
## Preparar el teléfono
|
|
222
|
+
|
|
223
|
+
1. Conecta un cable USB de datos y desbloquea el teléfono.
|
|
224
|
+
2. Activa **Opciones de desarrollador**. Habitualmente: Ajustes → Acerca del teléfono → Información de software → pulsa siete veces **Número de compilación**. La ubicación depende del fabricante.
|
|
225
|
+
3. En Opciones de desarrollador activa **Depuración USB**.
|
|
226
|
+
4. Acepta en el teléfono **Permitir depuración USB** para tu equipo. Puedes marcar que recuerde ese equipo si es tu ordenador de confianza.
|
|
227
|
+
5. Comprueba la conexión:
|
|
228
|
+
|
|
229
|
+
```sh
|
|
230
|
+
adb devices -l
|
|
231
|
+
wargaming-overlay doctor
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
6. Abre Tabletop Battles en una partida y selecciona la ronda que quieres emitir. Mantén el teléfono desbloqueado y la app visible.
|
|
235
|
+
|
|
236
|
+
`device` significa conectado y autorizado; `unauthorized` significa que falta aceptar el permiso; `offline` significa que ADB no puede comunicarse correctamente. Si la lista está vacía, ADB no distingue entre cable ausente, cable sin datos y depuración desactivada. [Guía oficial de conexión](https://developer.android.com/studio/run/device).
|
|
237
|
+
|
|
238
|
+
## Primer inicio y configuración de OBS
|
|
239
|
+
|
|
240
|
+
1. Detén cualquier lector anterior con Ctrl+C. No ejecutes dos lectores UIAutomator contra el mismo teléfono.
|
|
241
|
+
2. Si tienes datos de una versión anterior, [migra antes del primer inicio](#migrar-guardar-y-restablecer).
|
|
242
|
+
3. Inicia:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
wargaming-overlay start
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
4. Abre el panel en [http://127.0.0.1:8765](http://127.0.0.1:8765).
|
|
249
|
+
5. Configura título, nombres, facciones, disposiciones y destacamentos. Si el nombre visible del overlay es distinto al de la app, completa **Nombre en la app** para cada jugador. Pulsa **Actualizar overlay**.
|
|
250
|
+
6. En OBS añade una fuente **Navegador**, desmarca **Archivo local** y usa:
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
http://127.0.0.1:8765/overlay-art.html
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
7. Configura el **ancho y alto de la fuente** según tu lienzo. El selector del panel muestra las medidas; no modifica OBS por sí mismo.
|
|
257
|
+
8. En el teléfono, desplázate para mostrar el nombre y los bloques de datos de cada jugador. En pocos segundos aparecerán las lecturas.
|
|
258
|
+
9. Mantén la terminal abierta. Ctrl+C detiene servidor y lector; el estado queda guardado.
|
|
259
|
+
|
|
260
|
+
La asignación izquierda/derecha se hace por nombre, no por posición en el teléfono. Ignora mayúsculas y espacios adicionales; no adivina apodos. Dos nombres ambiguos no se vinculan. `—` significa que no hay lectura, no cero.
|
|
261
|
+
|
|
262
|
+
### Resoluciones
|
|
263
|
+
|
|
264
|
+
| Formato | Ancho | Alto |
|
|
265
|
+
| --- | ---: | ---: |
|
|
266
|
+
| 720p | 1280 | 720 |
|
|
267
|
+
| 900p | 1600 | 900 |
|
|
268
|
+
| 936p | 1664 | 936 |
|
|
269
|
+
| 1080p | 1920 | 1080 |
|
|
270
|
+
| 1440p — referencia original | 2560 | 1440 |
|
|
271
|
+
| 4K UHD | 3840 | 2160 |
|
|
272
|
+
|
|
273
|
+
El diseño **original a 2560×1440** es la referencia. En las otras resoluciones se escala todo proporcionalmente: fuentes, posiciones, iconos y separaciones. No reorganiza los elementos. Se verificó la igualdad geométrica con el original a 1440p y el escalado proporcional a 720p, 1080p y 4K.
|
|
274
|
+
|
|
275
|
+
Con otra relación de aspecto mantiene 16:9, centrado horizontalmente y alineado arriba, dejando espacio transparente. No hay una composición vertical dedicada. El soporte del overlay no garantiza que YouTube/Twitch acepten esa resolución para tu cuenta; configura la salida y el bitrate en OBS de forma independiente.
|
|
276
|
+
|
|
277
|
+
## Comandos y ejemplos
|
|
278
|
+
|
|
279
|
+
| Comando | Acción |
|
|
280
|
+
| --- | --- |
|
|
281
|
+
| `wargaming-overlay start` | Inicia servidor y lector. Es el comando predeterminado. |
|
|
282
|
+
| `wargaming-overlay doctor` | Comprueba Python, ADB y estado del dispositivo. |
|
|
283
|
+
| `wargaming-overlay setup` | Muestra la guía de tu sistema y ejecuta diagnóstico; no instala nada. |
|
|
284
|
+
| `wargaming-overlay setup --dry-run` | Muestra el plan sin instalar ni consultar ADB. |
|
|
285
|
+
| `wargaming-overlay setup --install-adb` | Instala ADB si falta y hay un gestor compatible; después diagnostica. |
|
|
286
|
+
| `wargaming-overlay migrate CARPETA` | Copia el estado anterior sin sobrescribir archivos existentes. |
|
|
287
|
+
| `wargaming-overlay --help` | Muestra ayuda. |
|
|
288
|
+
| `wargaming-overlay --version` | Muestra versión. |
|
|
289
|
+
|
|
290
|
+
`setup --install-adb` usa Homebrew, WinGet, apt-get, dnf o pacman según la plataforma. No instala Node, Python ni gestores de paquetes; no activa opciones de Android, no acepta autorizaciones USB ni acuerdos por ti. Puede pedir permisos del sistema. Si termina instalando pero todavía no detecta ADB, abre otra terminal y ejecuta `doctor`.
|
|
291
|
+
|
|
292
|
+
`doctor` y `setup` devuelven código 1 si el diagnóstico no está listo, incluso si solo falta conectar el teléfono. Con ADB/Python instalados, `start` conserva el panel abierto y reintenta aunque falte el teléfono.
|
|
293
|
+
|
|
294
|
+
### Opciones
|
|
295
|
+
|
|
296
|
+
| Opción | Valor predeterminado | Uso |
|
|
297
|
+
| --- | --- | --- |
|
|
298
|
+
| `--port` | `8765` | Puerto de `start`, entero entre 1024 y 65535. |
|
|
299
|
+
| `--interval` | `3` | Pausa entre lecturas de `start`, entre 1 y 60 segundos. Se suma al tiempo de captura. |
|
|
300
|
+
| `--serial` | Selección automática si hay uno | Dispositivo para `start`, `doctor` o `setup`. |
|
|
301
|
+
| `--adb` | Autodetección | Ruta al ejecutable ADB para `start`, `doctor` o `setup`. |
|
|
302
|
+
| `--python` | Autodetección | Ruta al ejecutable Python para `start`, `doctor` o `setup`. |
|
|
303
|
+
| `--data-dir` | Según el sistema | Carpeta de datos para `start` y destino de `migrate`. |
|
|
304
|
+
|
|
305
|
+
Las opciones no se guardan como configuración del CLI: repítelas en futuros inicios si quieres mantener un puerto, serial o ruta distintos.
|
|
306
|
+
|
|
307
|
+
Puerto alternativo y lectura menos frecuente:
|
|
308
|
+
|
|
309
|
+
```sh
|
|
310
|
+
wargaming-overlay start --port 8766 --interval 5
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
En OBS usa entonces `http://127.0.0.1:8766/overlay-art.html`.
|
|
314
|
+
|
|
315
|
+
Varios dispositivos:
|
|
316
|
+
|
|
317
|
+
```sh
|
|
318
|
+
adb devices -l
|
|
319
|
+
wargaming-overlay doctor --serial SERIAL_DEL_TELEFONO
|
|
320
|
+
wargaming-overlay start --serial SERIAL_DEL_TELEFONO
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Rutas explícitas, útiles si no están en PATH:
|
|
324
|
+
|
|
325
|
+
```sh
|
|
326
|
+
wargaming-overlay start --adb "$HOME/Android/platform-tools/adb" --python /usr/local/bin/python3
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
En Windows, sustituye las rutas de ejemplo por las reales:
|
|
330
|
+
|
|
331
|
+
```powershell
|
|
332
|
+
wargaming-overlay.cmd start --adb "C:\Android\platform-tools\adb.exe" --python "C:\Python312\python.exe"
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Carpeta independiente para pruebas:
|
|
336
|
+
|
|
337
|
+
```sh
|
|
338
|
+
wargaming-overlay start --data-dir "./datos-de-prueba" --port 8766
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
No ejecutes esa instancia al mismo tiempo que otra que esté leyendo el mismo teléfono.
|
|
342
|
+
|
|
343
|
+
## Migrar, guardar y restablecer
|
|
344
|
+
|
|
345
|
+
### Migración
|
|
346
|
+
|
|
347
|
+
Detén el servidor anterior. La carpeta de origen debe contener `overlay-state.json`, `game-state.json` o ambos:
|
|
348
|
+
|
|
349
|
+
```sh
|
|
350
|
+
wargaming-overlay migrate "/ruta/al/overlay-anterior"
|
|
351
|
+
wargaming-overlay start
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Windows:
|
|
355
|
+
|
|
356
|
+
```powershell
|
|
357
|
+
wargaming-overlay.cmd migrate "C:\Users\Ana\Documents\overlay-anterior"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
La migración **copia**, no elimina el original. Se niega a sobrescribir archivos existentes en el destino. Si ya iniciaste el nuevo servidor y quieres conservar también ese estado, usa un destino nuevo:
|
|
361
|
+
|
|
362
|
+
```sh
|
|
363
|
+
wargaming-overlay migrate "/ruta/al/overlay-anterior" --data-dir "./partida-importada"
|
|
364
|
+
wargaming-overlay start --data-dir "./partida-importada"
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
No migra archivos HTML/CSS ni imágenes personalizadas: el paquete trae sus propios recursos. Para importar esas personalizaciones se requiere trabajar sobre el código fuente.
|
|
368
|
+
|
|
369
|
+
### Ubicación de los datos
|
|
370
|
+
|
|
371
|
+
| Sistema | Carpeta predeterminada |
|
|
372
|
+
| --- | --- |
|
|
373
|
+
| macOS | `~/Library/Application Support/wargaming-overlay` |
|
|
374
|
+
| Windows | `%LOCALAPPDATA%\wargaming-overlay` |
|
|
375
|
+
| Linux | `$XDG_DATA_HOME/wargaming-overlay`, o `~/.local/share/wargaming-overlay` |
|
|
376
|
+
|
|
377
|
+
`overlay-state.json` contiene los nombres, vínculos y apariencia. `game-state.json` guarda la última partida leída. Están fuera de la instalación npm para sobrevivir a las actualizaciones. Para hacer un respaldo consistente, detén el servidor y copia ambos archivos. Usa `--data-dir` si quieres conservar la ubicación de una instalación anterior al cambio de nombre.
|
|
378
|
+
|
|
379
|
+
### Persistencia y reset
|
|
380
|
+
|
|
381
|
+
Si desconectas el teléfono, abres otra pantalla o falla una captura, el overlay conserva el último estado. El panel informa del problema. Reiniciar el servidor vuelve a cargar el estado guardado.
|
|
382
|
+
|
|
383
|
+
El botón **Restablecer datos de la partida** vacía los puntos y misiones guardados, sin cambiar nombres, facciones ni diseño. Si el teléfono sigue conectado, la próxima lectura volverá a completar lo visible. Restablece cuando empieces una nueva partida con los mismos jugadores.
|
|
384
|
+
|
|
385
|
+
### Qué se puede leer
|
|
386
|
+
|
|
387
|
+
- Marcador, nombres y ronda de la pantalla abierta.
|
|
388
|
+
- CP, totales de primaria/secundaria y misiones visibles cuando se identifica su jugador.
|
|
389
|
+
- Casilla marcada o pendiente en las primarias que la exponen; contador cuando la interfaz expone uno.
|
|
390
|
+
- Puntos y máximo en las secundarias que los exponen.
|
|
391
|
+
|
|
392
|
+
Solo lee lo visible. Un bloque sin nombre de jugador se ignora para evitar asignaciones incorrectas. Los datos conservados pueden haber cambiado fuera de pantalla y las listas de misiones pueden ser parciales. No interpreta una lista ausente como lista vacía.
|
|
393
|
+
|
|
394
|
+
Al cambiar de ronda no reutiliza CP ni misiones de la ronda anterior. Si consultas una ronda histórica en el teléfono, mostrará esa ronda. No infiere TOP/BOTTOM ni quién está jugando por el puntaje. El nombre general de la primaria no siempre está expuesto; se muestran sus condiciones de puntuación.
|
|
395
|
+
|
|
396
|
+
## Solución de problemas
|
|
397
|
+
|
|
398
|
+
| Problema | Qué hacer |
|
|
399
|
+
| --- | --- |
|
|
400
|
+
| `wargaming-overlay: command not found` | Comprueba la instalación con `npm list -g --depth=0`. Revisa PATH y abre otra terminal. En Unix, los ejecutables están bajo `bin` del prefijo mostrado por `npm prefix -g`; en Windows, en el propio prefijo. |
|
|
401
|
+
| PowerShell bloquea un `.ps1` | Usa `npm.cmd` y `wargaming-overlay.cmd`. |
|
|
402
|
+
| npm devuelve EACCES | Usa la instalación en `~/.local` descrita arriba. No inicies el servidor con sudo. |
|
|
403
|
+
| npm devuelve 404 | El paquete puede no estar publicado o el scope ser distinto. Instala desde el código fuente o `.tgz`. |
|
|
404
|
+
| ADB no encontrado | Ejecuta `setup --install-adb`, instala Platform-Tools o pasa `--adb` con la ruta completa. |
|
|
405
|
+
| Python ausente/incompatible | Instala Python 3.8+ y usa `--python` si tienes varias instalaciones. En Windows prueba `py -3 --version`. |
|
|
406
|
+
| No aparece ningún teléfono | Revisa cable de datos, puerto USB, desbloqueo y depuración USB. En Windows comprueba drivers. |
|
|
407
|
+
| `unauthorized` | Desbloquea el teléfono y acepta el permiso de depuración para este equipo. Reconecta el cable si no aparece. |
|
|
408
|
+
| `offline` | Desbloquea y reconecta el teléfono. |
|
|
409
|
+
| `no permissions` en Linux | Revisa reglas udev y grupos. En Ubuntu instala `android-sdk-platform-tools-common` y comprueba `plugdev`. |
|
|
410
|
+
| Hay varios dispositivos | Usa `adb devices -l` y pasa `--serial`. Incluye emuladores en esta comprobación. |
|
|
411
|
+
| El puerto está ocupado | Detén la otra instancia o usa `--port 8766` y actualiza la URL de OBS. |
|
|
412
|
+
| No se puede leer Android / error 137 | Abre la ronda, desbloquea el teléfono y cierra otros lectores UIAutomator. El CLI reintenta. |
|
|
413
|
+
| Los valores están en `—` | Revisa «Nombre en la app» y muestra el nombre y bloque del jugador en la pantalla del teléfono. |
|
|
414
|
+
| No cambia un dato | Desplázate para que sea visible; los valores fuera de pantalla pueden ser la última lectura guardada. |
|
|
415
|
+
| OBS está vacío | Comprueba que el servidor esté abierto, que el panel responda y que la URL y puerto coincidan. Desmarca Archivo local y refresca la fuente. |
|
|
416
|
+
| El diseño no refleja cambios | Refresca la fuente. Si editaste el código pero ejecutas un paquete global copiado, reinstala desde ese código. |
|
|
417
|
+
| El reset se llena de nuevo | Es normal si el teléfono sigue conectado: la siguiente captura rellena los datos visibles. |
|
|
418
|
+
| Migración rechazada | Ya existen archivos de estado en el destino. Usa una carpeta nueva con `--data-dir`. |
|
|
419
|
+
|
|
420
|
+
## Actualizar y desinstalar
|
|
421
|
+
|
|
422
|
+
Detén el servidor con Ctrl+C antes de actualizar. Desde el código fuente actualizado:
|
|
423
|
+
|
|
424
|
+
```sh
|
|
425
|
+
npm install -g .
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Desde npm, cuando exista el paquete publicado:
|
|
429
|
+
|
|
430
|
+
```sh
|
|
431
|
+
npm install -g @ing.jorgeu/wargaming-overlay@latest
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Si usaste un prefijo de usuario, repite `--prefix "$HOME/.local"`. Después inicia otra vez y refresca la fuente en OBS.
|
|
435
|
+
|
|
436
|
+
Para desinstalar el CLI:
|
|
437
|
+
|
|
438
|
+
```sh
|
|
439
|
+
npm uninstall -g @ing.jorgeu/wargaming-overlay
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
O, con el prefijo de usuario:
|
|
443
|
+
|
|
444
|
+
```sh
|
|
445
|
+
npm uninstall -g --prefix "$HOME/.local" @ing.jorgeu/wargaming-overlay
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
La desinstalación no borra tus archivos de partida ni desinstala ADB, Python u OBS. Puedes conservar la carpeta de datos como respaldo.
|
|
449
|
+
|
|
450
|
+
## Desarrollo y publicación
|
|
451
|
+
|
|
452
|
+
Desde la raíz del repositorio:
|
|
453
|
+
|
|
454
|
+
```sh
|
|
455
|
+
npm test
|
|
456
|
+
node cli.js setup --dry-run
|
|
457
|
+
npm pack --dry-run
|
|
458
|
+
npm pack
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
`npm pack` genera el `.tgz` instalable. `npm pack --dry-run` lista el contenido sin crear ese archivo. No hay un paso de compilación ni dependencias npm que descargar para ejecutar las pruebas; estas sí necesitan Python.
|
|
462
|
+
|
|
463
|
+
La matriz de `.github/workflows/test.yml` está preparada para Node 20/22/24 en Windows, macOS y Linux. Las pruebas cubren diagnósticos, rutas, selección de instaladores, parser y estado guardado. No sustituyen las pruebas físicas de USB ni de emisión con OBS.
|
|
464
|
+
|
|
465
|
+
Consulta [PUBLISHING.md](PUBLISHING.md) para autenticarte y publicar. `npm publish` sube el paquete realmente; no es un paso necesario para usarlo localmente. El scope debe ser tuyo o de una organización en la que tengas permiso. No se han incluido credenciales en el proyecto.
|
|
466
|
+
|
|
467
|
+
## Licencia y recursos
|
|
468
|
+
|
|
469
|
+
El código se distribuye bajo **[0BSD](LICENSE)**, una licencia permisiva que permite uso comercial, modificación y redistribución sin atribución obligatoria y sin garantías. [Texto oficial](https://opensource.org/license/0bsd).
|
|
470
|
+
|
|
471
|
+
Se conservan las imágenes del overlay. Su procedencia y derechos se documentan por separado en [THIRD_PARTY_ASSETS.md](THIRD_PARTY_ASSETS.md); la licencia del código no concede derechos adicionales sobre recursos de terceros. El proyecto no declara afiliación oficial con las aplicaciones o juegos a los que hace referencia.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Recursos visuales
|
|
2
|
+
|
|
3
|
+
Los PNG de `public/assets/` proceden del overlay local del usuario. Este proyecto no contiene documentación que establezca su autoría, licencia o permiso para redistribuirlos públicamente.
|
|
4
|
+
|
|
5
|
+
Antes de publicar el paquete, el titular debe revisar los recursos y añadir las atribuciones/licencias pertinentes o reemplazarlos por recursos redistribuibles. La licencia **0BSD** del código no concede derechos sobre imágenes de terceros.
|
|
6
|
+
|
|
7
|
+
Los nombres de facciones se usan como referencias descriptivas. El paquete no declara afiliación oficial.
|
package/battle_reader.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Local Tabletop Battles reader. Python standard library only."""
|
|
3
|
+
import os, argparse, copy, functools, http.server, json, pathlib, re, subprocess, threading, time, xml.etree.ElementTree as ET
|
|
4
|
+
ROOT = pathlib.Path(__file__).resolve().parent
|
|
5
|
+
|
|
6
|
+
def parse(xml):
|
|
7
|
+
root = ET.fromstring(xml)
|
|
8
|
+
nodes = [n for n in root.iter('node') if n.get('package') == 'com.goonhammer.ttba' and (n.get('content-desc') or n.get('text'))]
|
|
9
|
+
texts = [(n.get('content-desc') or n.get('text')).strip() for n in nodes]
|
|
10
|
+
header = next((re.fullmatch(r'(\d+)\s*[-–]\s*(\d+)\s+(.+?) vs (.+)', t) for t in texts if re.fullmatch(r'(\d+)\s*[-–]\s*(\d+)\s+(.+?) vs (.+)', t)), None)
|
|
11
|
+
rnd = next((int(m[1]) for t in texts if (m := re.fullmatch(r'Round (\d+)', t))), None)
|
|
12
|
+
if not header or rnd is None: raise ValueError('Abre una ronda de Tabletop Battles, sin menús encima.')
|
|
13
|
+
players = [dict(name=header[i+3], score=int(header[i+1]), cp=None, primary=None, secondary=None, secondaries=None, primaryObjectives=None) for i in range(2)]
|
|
14
|
+
names = [p['name'] for p in players]
|
|
15
|
+
if names[0] == names[1]: raise ValueError('Usa nombres distintos para identificar a los jugadores.')
|
|
16
|
+
current = None
|
|
17
|
+
section = None
|
|
18
|
+
for i, t in enumerate(texts):
|
|
19
|
+
if t in names:
|
|
20
|
+
current = players[names.index(t)]
|
|
21
|
+
section = None
|
|
22
|
+
if current is None: continue # Never assign a clipped block to a guessed player.
|
|
23
|
+
if t.lower() == 'cp' and i and texts[i-1].isdigit(): current['cp'] = int(texts[i-1])
|
|
24
|
+
m = re.fullmatch(r'(PRIMARY|SECONDARY):\s*(\d+)/(\d+)', t)
|
|
25
|
+
if m:
|
|
26
|
+
section = m[1]
|
|
27
|
+
current[m[1].lower()] = {'score': int(m[2]), 'max': int(m[3])}
|
|
28
|
+
if section == 'PRIMARY':
|
|
29
|
+
details = re.fullmatch(r'(.+)\n(\d+VP.*)', t)
|
|
30
|
+
if not details and i+1 < len(texts) and re.match(r'\d+VP', texts[i+1]):
|
|
31
|
+
details = (None, t, texts[i+1])
|
|
32
|
+
if details:
|
|
33
|
+
if current['primaryObjectives'] is None: current['primaryObjectives'] = []
|
|
34
|
+
checkboxes = [n for n in nodes[i].iter('node') if n.get('checkable') == 'true']
|
|
35
|
+
checked = checkboxes[0].get('checked') == 'true' if len(checkboxes) == 1 else None
|
|
36
|
+
counter = None
|
|
37
|
+
# Split counter rows expose label, scoring rule, then numeric value.
|
|
38
|
+
if '\n' not in t and i+2 < len(texts) and texts[i+2].isdigit():
|
|
39
|
+
counter = int(texts[i+2])
|
|
40
|
+
current['primaryObjectives'].append({'name': details[1], 'details': details[2], 'checked': checked, 'counter': counter})
|
|
41
|
+
m = re.fullmatch(r'(.+)\n(\d+)\n/(\d+)(?:\n\+(\d+)pts)?', t)
|
|
42
|
+
if m:
|
|
43
|
+
if current['secondaries'] is None: current['secondaries'] = []
|
|
44
|
+
current['secondaries'].append(dict(name=m[1], score=int(m[2]), max=int(m[3])))
|
|
45
|
+
return dict(round=rnd, half=None, players=players)
|
|
46
|
+
|
|
47
|
+
def merge(previous, fresh):
|
|
48
|
+
now = time.time()
|
|
49
|
+
same = previous and previous['round'] == fresh['round'] and [p['name'] for p in previous['players']] == [p['name'] for p in fresh['players']]
|
|
50
|
+
for i, player in enumerate(fresh['players']):
|
|
51
|
+
stamps = {}
|
|
52
|
+
for key in ('cp', 'primary', 'secondary', 'secondaries'):
|
|
53
|
+
if player[key] is not None: stamps[key] = now
|
|
54
|
+
elif same:
|
|
55
|
+
player[key] = copy.deepcopy(previous['players'][i][key])
|
|
56
|
+
stamps[key] = previous['players'][i].get('observedAt', {}).get(key)
|
|
57
|
+
player['observedAt'] = stamps
|
|
58
|
+
return dict(fresh, updatedAt=now, connected=True, error=None)
|
|
59
|
+
|
|
60
|
+
def save(state):
|
|
61
|
+
temp = ROOT / 'game-state.tmp'
|
|
62
|
+
temp.write_text(json.dumps(state, ensure_ascii=False, indent=2))
|
|
63
|
+
temp.replace(ROOT / 'game-state.json')
|
|
64
|
+
|
|
65
|
+
def adb(serial, *args):
|
|
66
|
+
return subprocess.run([os.environ.get('OVERLAY_ADB', 'adb'), '-s', serial, *args], check=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=18).stdout
|
|
67
|
+
|
|
68
|
+
def capture(serial):
|
|
69
|
+
adb(serial, 'shell', 'uiautomator', 'dump', '/sdcard/codex-ttba.xml')
|
|
70
|
+
return adb(serial, 'exec-out', 'cat', '/sdcard/codex-ttba.xml')
|
|
71
|
+
|
|
72
|
+
class Handler(http.server.SimpleHTTPRequestHandler):
|
|
73
|
+
def do_GET(self):
|
|
74
|
+
if self.path.split('?')[0] not in ('/', '/overlay.html', '/style.css', '/overlay.js', '/game-state.json'): self.send_error(404); return
|
|
75
|
+
if self.path == '/': self.path = '/overlay.html'
|
|
76
|
+
super().do_GET()
|
|
77
|
+
def end_headers(self):
|
|
78
|
+
self.send_header('Cache-Control', 'no-store'); super().end_headers()
|
|
79
|
+
def log_message(self, *args): pass
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
p = argparse.ArgumentParser()
|
|
83
|
+
p.add_argument('--serial'); p.add_argument('--interval', type=float, default=3)
|
|
84
|
+
p.add_argument('--port', type=int, default=8765); p.add_argument('--once', action='store_true')
|
|
85
|
+
args = p.parse_args()
|
|
86
|
+
devices = subprocess.run(['adb', 'devices'], capture_output=True, text=True, check=True).stdout
|
|
87
|
+
serials = [line.split()[0] for line in devices.splitlines() if '\tdevice' in line]
|
|
88
|
+
serial = args.serial or (serials[0] if len(serials) == 1 else None)
|
|
89
|
+
if not serial: p.error('Conecta y autoriza exactamente un teléfono, o usa --serial.')
|
|
90
|
+
state = None
|
|
91
|
+
if not args.once:
|
|
92
|
+
server = http.server.ThreadingHTTPServer(('127.0.0.1', args.port), functools.partial(Handler, directory=str(ROOT)))
|
|
93
|
+
threading.Thread(target=server.serve_forever, daemon=True).start()
|
|
94
|
+
print(f'Overlay: http://127.0.0.1:{args.port}/overlay.html · Ctrl+C para detener', flush=True)
|
|
95
|
+
try:
|
|
96
|
+
while True:
|
|
97
|
+
start = time.monotonic()
|
|
98
|
+
try:
|
|
99
|
+
state = merge(state, parse(capture(serial)))
|
|
100
|
+
save(state)
|
|
101
|
+
print(f"Ronda {state['round']}: " + ' / '.join(f"{x['name']} {x['score']}" for x in state['players']), flush=True)
|
|
102
|
+
except (ValueError, ET.ParseError, subprocess.SubprocessError, OSError) as e:
|
|
103
|
+
print(str(e), flush=True)
|
|
104
|
+
if state: state.update(connected=False, error=str(e)); save(state)
|
|
105
|
+
if args.once: raise
|
|
106
|
+
if args.once: break
|
|
107
|
+
time.sleep(max(1, args.interval - (time.monotonic() - start)))
|
|
108
|
+
except KeyboardInterrupt: pass
|
|
109
|
+
|
|
110
|
+
if __name__ == '__main__': main()
|