Завантаження перекладу в рантаймі: від розпакованої гри до ASI
Ця сторінка описує, як переклад потрапляє в гру, які функції рушія для цього знайдено і як змінювався спосіб постачання від 0.1.0 до 1.1.10. Загальну картину модулів див. в architecture.md.
Етап 1: розпакована гра (0.1.0–0.1.5)
Розділ «Етап 1: розпакована гра (0.1.0–0.1.5)»Рання гіпотеза проєкту: гра читає файли з STUFF/TEXT/ поверх GAME.DAT.
Перша спроба встановити переклад так нічого не змінила.
Реальна поведінка: рушій читає звичайні файли лише тоді, коли відповідного
DAT немає на диску. Тому ранні версії вимагали розпакувати всі чотири DAT
у теку гри (десятки тисяч файлів, кілька гігабайтів), перейменувати архіви
на *.DAT.original_backup і накласти переклад. Пакет важив 182 МБ, а
встановлення було незручним і ризикованим.
Етап 2: UAP і перехоплення читання (0.1.6–0.1.7)
Розділ «Етап 2: UAP і перехоплення читання (0.1.6–0.1.7)»Ідея: лишити оригінальні DAT, а потрібні файли віддавати рушію з пам’яті.
Для цього дизасемблюванням знайдено функції ресурсної підсистеми
(адреси для Steam EXE з image base 0x400000):
| VA | Роль |
|---|---|
0x6B44F0 |
відкриття ресурсу: з DAT або за файловим шляхом |
0x6B46D0 |
перевірка існування |
0x6B4750 |
розмір за шляхом |
0x6B7440 |
завантаження цілого ресурсу (з прямою гілкою читання DAT) |
0x6B0250 |
розмір відкритого ресурсу |
0x6AA040 |
відкриття буфера пам’яті як ресурсу (memory stream) |
0x6B55A0 |
читання |
0x6B04C0 |
позиціювання |
0x6B38F0 |
закриття |
Плагін ставить x86 detour на ці функції. Для відомих шляхів
(STUFF/TEXT/ENGLISH.TXT, шрифти, титри) він створює рідний memory stream
рушія над даними з UAP, тож гра читає їх своїми ж функціями. Усі інші
ресурси проходять через trampoline до оригінального коду.
Дві знахідки, без яких це не працювало:
- CSV читався в обхід відкриття. Прототип із трьома перехопленнями вже
показував український основний текст і шрифт, але
TRC.CSVлишався англійським. Причина — окрема гілка прямого читання DAT у0x6B7440. Додано окреме перехоплення цієї функції. - Розмір на один байт менший. Memory stream рушія зберігає inclusive end,
а
0x6B0250повертаєend − start. Для наших буферів розмір коригується до довжини запису UAP; чужі дескриптори не чіпаються.
Рушій має пул із 20 слотів для буферних потоків. Якщо пул вичерпано, плагін пише про це в журнал і повертається до штатного відкриття.
У 0.1.7 до цього додалася підміна DDS у буфері читання (функція 0x6B55A0,
вкрадені інструкції 51 8B 44 24 08). Подробиці — у textures.md.
Запобіжники
Розділ «Запобіжники»Перед будь-якою зміною плагін перевіряє:
- SHA-256
LEGOIndy.exe(c12f7348…332e5e5fd); - початкові байти кожної функції, яку перехоплює;
- SHA-256 кожного запису UAP.
Якщо хоч щось не збігається, переклад не вмикається, а гра працює як оригінал. Це перевірено тестами з відсутнім і пошкодженим UAP: усі шість функцій і 76 PC-вказівників лишаються незмінними.
Етап 3: ASI-плагін (0.1.8 і далі)
Розділ «Етап 3: ASI-плагін (0.1.8 і далі)»У 0.1.6–0.1.7 наша dinput8.dll була proxy-бібліотекою: надавала експорти
DirectInput, завантажувала системну бібліотеку й передавала їй виклики. Мінус —
з іншим модом, якому теж потрібен dinput8.dll, переклад не співіснував.
З 0.1.8 dinput8.dll — офіційний Ultimate ASI Loader
9.7.4 без змін, а переклад — плагін scripts/UKRAINIAN.asi. Перед вибором
перевірено код саме тега v9.7.4, а не README гілки master:
- після завантаження ASI loader викликає недекорований експорт
InitializeASI; - зі стандартним
DontLoadFromDllMain=1запуск плагінів відкладається до викликів гри, і loader враховує захисну секцію Steam.bind.
Наш плагін:
- у
DllMainлише запам’ятовує модуль, уся робота — вInitializeASI; - через
InitOnceExecuteOnceініціалізується рівно один раз, навіть якщо інший мод викличеInitializeASIповторно; - закріплює себе в пам’яті до кінця процесу, бо таблиці гри й trampolines посилаються на його код і дані;
- шукає
UKRAINIAN.uapпоруч із собою, а не в робочій теці; - пише журнал у
scripts/legoindy-ua-pc.log; - імпортує лише
KERNEL32іbcrypt(SHA-256), експортує лишеInitializeASI.
| Перевірка 0.1.8 | Результат |
|---|---|
| Основні тексти в пам’яті | 598/598 |
| CSV у пам’яті | 194/194 |
| PC-рядки | 38/38; 76 вихідних і 38 активних вказівників |
| Потоки UAP (read/size/seek/EOF/close, 32 повторні відкриття) | 21/21 |
| Другий незалежний ASI | завантажився й відпрацював разом із нашим |
Повторний виклик InitializeASI |
одна ініціалізація |
| UAP відсутній чи пошкоджений | гра оригінальна |
| Невідомий EXE | пропуск без патчів |
Сумісність з іншими модами
Розділ «Сумісність з іншими модами»ASI знімає конфлікт за ім’я dinput8.dll, але не всі конфлікти:
ENGLISH.TXT,TRC.CSVі шрифти з UAP підміняються цілими файлами. Текстові моди (наприклад, Archeologist Edition змінює назви вenglish.txt) потребуватимуть злиття.- Мод, що змінює ті самі DDS, матиме пріоритет: плагін не впізнає змінених пікселів і пропустить підміну.
- Loose-файли в
CHARS/чиLEVELS/при активних DAT не діють; таким модам потрібна розпакована гра або редиректор. - Будь-яка зміна EXE на диску, зокрема LAA-патч, змінює SHA-256, і плагін вимикається.
Комбінації зі сторонніми модпаками наживо не перевірялися.
Мова системи: англійська (Велика Британія) чи англійська (США)
Розділ «Мова системи: англійська (Велика Британія) чи англійська (США)»Під час перевірки на Steam Deck автор помітив, що частина тексту лишається англійською, хоча той самий пакет на Windows-ПК працював повністю. Причина виявилася не в адресах пам’яті й не в Proton як такому.
LEGOIndy.exeвизначає мову черезGetUserDefaultLangID. У бінарнику окремо прописаноstuff\text\american.txt.- Для англійської (США) гра спершу читає
ENGLISH.TXT, а потім поверх ньогоAMERICAN.TXT. Це надбудова лише з 18 рядків з американським написанням («Artifact», «Theater», підказки про лопату тощо). Крім того, гра бере колонку AMERICAN зTRC.CSV(усі діалоги збереження й завантаження, «Press a key or controller button…») іAMERICAN_CREDITS.TXTзамість наших титрів. - Proton на Steam Deck за замовчуванням працює як en-US. На ПК автора мова системи
інша, тому гра обирала британський варіант, і все було перекладено. Параметр
запуску
LANG=en_GB.UTF-8на Deck не допоміг, тож на вибір мови в Proton він не впливає.
Рішення (1.1.10): плагін віддає будь-який файл, який є в пакеті, тож нативний
код змінювати не довелося. У UKRAINIAN.uap додано перекладені AMERICAN.TXT і
AMERICAN_CREDITS.TXT, а TRC.CSV отримує переклад в обидві англійські колонки,
ENGLISH і AMERICAN. Шаблони американських файлів один раз беруться з видобутої гри
(manifests/game-files.json); у наступних релізах вони вже будуть у базовому пакеті.
Значок рейтингу ESRB на американському стартовому екрані свідомо не перемальовано:
це знак рейтингової організації. Текст самого екрана (T2748) перекладено.
Урок діагностики: пауза перед катсценами
Розділ «Урок діагностики: пауза перед катсценами»Після переходу на UAP автор помітив паузу близько 15 секунд перед катсценами. Логічна підозра падала на плагін. Контрольні запуски показали інше:
- Без
UKRAINIAN.asiпауза лишилася. - Без
dinput8.dll(у процесі — системнаDINPUT8.dll) пауза лишилася. - Порівняння з маніфестом Steam-депо виявило, що бракує 279 файлів теки
audio(883 МБ: OGG катсцен, музика). Їх помилково прибрав старий сценарій міграції з розпакованої гри.
Після відновлення аудіо (перевірка цілісності Steam) катсцени запрацювали
нормально, а переклад повернули. Висновок, який увійшов у процес: інструменти
встановлення для розробника звіряють контрольні суми файлів гри, яких не можна
чіпати (EXE, DAT, binkw32.dll, тека audio), до й після копіювання.
Для швидкого тестування в тій діагностиці існував режим автоматичного
завершення катсцен (за відкритою інструкцією спільноти змінювався предикат
0x6A0250). Він лишився експериментом і не входить до релізу.
Повні докази — в архіві досліджень автора.