cat ~/projects/luneta/README
Luneta
Agent w zasobniku systemowym dla gier gacha: zrzut okna na żądanie, lokalny OCR walut i liczników, checklista dniówek i synchronizacja z ariku.pl. Bez ingerencji w pamięć gry.
Cel
Gry gacha mają dziesiątki dziennych i tygodniowych zadań, walut i limitów czasowych. Luneta ma dać graczowi warstwę informacyjną (checklistę, przypomnienia, wsparcie streamowania) bez łamania zasad fair play: bez czytania pamięci procesu, bez obchodzenia anti-cheatu i bez automatyzowania rozgrywki.
Rozwiązanie
Aplikacja w trayu dla Blue Archive i Neverness to Everness. Robi zrzut okna gry na skrót klawiszowy albo w pętli z wykrywaniem stabilnego obrazu, lokalnie odczytuje liczby przez OCR, pokazuje okno potwierdzenia i dopiero wtedy wysyła dane na serwer. Prowadzi checklistę, kolejkuje zdarzenia offline i współpracuje z OBS.
Architektura
- Interfejs w React 19 i TypeScript w oknie Tauri 2, komunikacja z backendem przez komendy IPC.
- Rdzeń w Ruście niezależny od Tauri: przechwytywanie okna, wykrywanie procesów gry, klient OBS WebSocket, silnik OCR i skaner nagrań.
- Moduły gier implementują wspólny trait; nowe gry można dodać deklaratywnym pakietem game.json.
- SQLite buforuje zdarzenia i kolejkę offline; poświadczenia trzyma systemowy magazyn kluczy.
- Synchronizacja z API ariku.pl jest idempotentna dzięki identyfikatorom UUID nadawanym po stronie klienta.
Decyzje techniczne
- Tauri i Rust zamiast Electrona
- Mała binarka, natywny tray i jedna baza kodu dla Arch Linuksa (X11) i Windows 11.
- Lokalny, deterministyczny OCR
- ocrs (modele ONNX w czystym Ruście) i wzorce cyfr zamiast chmurowego LLM czy Tesseracta: zrzuty ekranu nie opuszczają komputera, a wynik jest powtarzalny.
- Atlas glifów dla Blue Archive
- Dopasowanie cyfr do atlasu przed uruchomieniem ocrs skróciło odczyt wycinka z 50–110 ms do mikrosekund przy pełnej zgodności odczytów.
- Dwuetapowa analiza nagrań
- Najpierw szybki skan głośności audio, potem dekodowanie wideo w niskiej rozdzielczości tylko wokół wykrytych momentów, zamiast analizować całe nagranie.
Problemy i rozwiązania
- Zalewanie API po błędzie 429
- Pętla wysyłała do 6 żądań na sekundę mimo limitu. Doszedł globalny cooldown (60 s albo wartość z nagłówka Retry-After), który wstrzymuje całą kolejkę.
- Czarny zrzut gier w trybie pełnoekranowym na Windows
- Gdy przechwycenie okna zwraca czarny obraz, Luneta robi zrzut monitora i przycina go do współrzędnych okna z uwzględnieniem skalowania DPI.