From 60910268230e3ae6d6c954727f3f02ec0665844c Mon Sep 17 00:00:00 2001 From: rouges78 Date: Fri, 21 Aug 2026 16:22:08 +0200 Subject: [PATCH] Record where the runtime chain actually stops on Unreal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First real-game test of the chain, on Father's Day. The transport half works: the DLL connects to the Rust server inside a shipping title, and the game stays healthy — SendMessageTimeout answers, 103s CPU, 608 MB. That confirms the overlapped-I/O fix on something other than the test app, which matters, because that bug froze the process instantly. The other half does not. Zero requests reach the server, because the Unreal L1 source refuses to hook FText::ToString when its byte pattern is ambiguous — four matches here — and declines rather than hooking the wrong function. The GDI sources stay active but see nothing: UE draws through Slate/Direct3D, not ExtTextOutW. The missing link is symbol resolution, not IPC. The trap is the log line "connesso a GameStringer via IPC", which reads like success and is only half the chain. The number that decides is how many requests reach the server; at zero, the problem is upstream of the IPC and staring at the pipe will never find it. Carries the corollary for #87: hooking the fallback to the "Unreal without .locres" dead end is right in principle, but while that pattern stays ambiguous the runtime path has no text to translate on UE, so it would offer a road that leads nowhere yet. RPG_RT and GDI games are different — that source works and has been seen working. Second entry, on the Paks folder: every UE game has at least two, and the first one found is usually the decoy — Engine/Programs/CrashReportClient/Content/Paks. I measured that one and concluded REANIMAL had no localization: 45 MB of crash reporter against 15.6 GB of game. The control that catches it is The Skin Stapler, which must come back positive at 1679 entries; while a method says otherwise, the method is what is broken. Co-Authored-By: Claude Opus 5 --- docs/METODI-DI-TRADUZIONE.md | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/docs/METODI-DI-TRADUZIONE.md b/docs/METODI-DI-TRADUZIONE.md index cdcad5f0..0718fe71 100644 --- a/docs/METODI-DI-TRADUZIONE.md +++ b/docs/METODI-DI-TRADUZIONE.md @@ -47,6 +47,19 @@ cercare le cartelle `Paks` — ricorsivo fino a 5 livelli, con verifica che la cartella contenga davvero `.pak`/`.utoc`. `find_paks_dir`, `find_utoc_files` e `find_pak_files` ci si appoggiano tutti. +**Seconda trappola, stessa cartella (21/08/2026).** Non è solo una questione di +profondità: ogni gioco UE ha **almeno due** cartelle `Paks`, e quella che si +incontra per prima è quasi sempre il richiamo sbagliato — +`Engine/Programs/CrashReportClient/Content/Paks`, decine di MB di crash +reporter. Misurando quella si conclude che il gioco non ha localizzazione: +REANIMAL dava 45 MB e «nessun locres» contro i 15,6 GB della cartella vera, e +TerraTech Legion 46 MB contro 5,5 GB. Chi scrive uno script di analisi deve +scartare i percorsi sotto `Engine/Programs`, non fermarsi al primo `Paks` +trovato — che è esattamente quello che fa `find_all_paks_dirs()`, e il motivo +per cui va usata quella invece di una `find` improvvisata. Il controllo che +smaschera l'errore: The Skin Stapler DEVE risultare positivo (1679 voci), e +finché un metodo dice il contrario è il metodo a essere rotto. + **Trappola.** Il sintomo era una contraddizione a schermo: il pulsante prometteva «.locres trovati», il pannello sotto negava. Erano **tre finder con due profondità diverse in due file diversi** — `find_paks_dir` cercava già in modo @@ -320,6 +333,56 @@ che prima o poi viene riempita, il dedup no: se la condizione che lo svuota può non verificarsi mai, serve una scadenza. Qui la condizione era "il server risponde", e sul miss il server tace per progetto. +### Su Unreal la catena runtime si ferma al pattern di `FText::ToString` + +**Il fatto.** Il trasporto funziona su un gioco vero — la DLL si connette al +server Rust e il gioco non ne risente — ma **non arriva testo**, perché la +sorgente L1 per Unreal si rifiuta di agganciare `FText::ToString` quando il +pattern di byte è ambiguo. Le sorgenti L2 (GDI) restano attive ma non vedono +nulla: UE disegna il testo via Slate/Direct3D, non con `ExtTextOutW`. L'anello +mancante non è l'IPC, è la risoluzione del simbolo. + +**Misura.** Father's Day (UE, Steam), 21 agosto 2026, iniezione reale nel +processo `Fathers_Day-Win64-Shipping.exe` con il server di prova in ascolto: + +```text +cargo run --example translator_pipe_server +gs-hook\build-x64\bin\Release\gs-injector.exe +``` + +Lato DLL (`%TEMP%\gs-hook.log`), quattro righe in tutto: + +```text +[gs-hook] connesso a GameStringer via IPC +[gs-hook/UE] pattern FText::ToString ambiguo: 4 match, hook RIFIUTATO + (aggancerebbe la funzione sbagliata) +[gs-hook] sorgente attiva: GDI (ExtTextOutW/DrawTextW) (livello 2) +[gs-hook] sorgente attiva: GDI/GetGlyphOutline (estrazione) (livello 2) +``` + +Lato server: `DLL connessa`, e **zero richieste**. Il gioco resta sano — +`SendMessageTimeout(WM_NULL, 3000ms)` risponde, 103 s di CPU, 608 MB — il che +conferma su un titolo vero la correzione dell'I/O overlapped (vedi la voce +sopra): quel bug congelava il processo all'istante. + +**Nel codice.** `gs-hook/src/sources/source_unreal_ftext.cpp` (livello Engine, +il rifiuto è deliberato), `gs-hook/src/sources/source_gdi.cpp` (livello +Rasterization, il ripiego universale). + +**La trappola.** «connesso a GameStringer via IPC» nel log sembra il segnale +che tutto funziona, ed è solo metà della catena: dice che il *trasporto* è +vivo, non che qualcuno gli stia parlando. Il numero che conta è quante +richieste arrivano al server — se è zero, il problema sta a monte dell'IPC, e +guardare la pipe non lo troverà mai. + +**Corollario sul fallback a runtime.** Agganciare il fallback al vicolo cieco +«Unreal senza `.locres`» (PR #87) è giusto in linea di principio, ma finché +il pattern di `FText::ToString` resta ambiguo **su UE il runtime non ha testo +da tradurre**: proporrebbe una strada che non porta ancora da nessuna parte. +Per RPG_RT e i giochi GDI la sorgente funziona ed è stata vista funzionare; +per UE no. Prima di considerare chiusa quella strada, va reso non ambiguo il +pattern (o sostituito con una risoluzione per simbolo). + --- ## Come si aggiunge una voce